Exclude specific keys or values from the original type
When you want to exclude certain attributes (Omit) or select (Pick), of course, you can Omit the < IOrigin, “key1” | “key2” >, but if have a way to batch processing, the following will show you SAO operation
interface IOrigin {
[name: number] :string
name: string
gender: string
age: number
getName: () = > string
getGener: () = > string
getAge: () = > number
}
* {* [name: number]: string; * gender: string; * age: number; * getGener: () => string; * getAge: () => number; *} * /
type OmitSimply = Omit<IOrigin, "name" | "getName">
// Infer excludes attributes of a specific Key
type OmitInferKey<T, R> = {
[K in keyof T as T extends R ? never : K]: T[K]
}
/** * exclude Key type number attributes * {* name: string; * gender: string; * age: number; * getName: () => string; * getGener: () => string; * getAge: () => number; *} * /
type OmitInferKeyNumber = OmitInferKey<IOrigin, number>
/** * exclude Key 'get${string}' attributes * {* [name: number]: string; * name: string; * gender: string; * age: number; *} * /
type OmitInferKeyRegExp = OmitInferKey<IOrigin, `getThe ${string}`>
// Infer excludes specific Value attributes
type OmitInferValue<T, R> = {
[K in keyof T as T[K] extends R ? never : K]: T[K]
}
* {* [name: number]: string; * name: string; * gender: string; * age: number; *} * /
type OmitInferKeyFunction = OmitInferValue<IOrigin, Function>
Copy the code
Here’s how to Omit anything and you can use one to “Pick” anything.
Some attributes of a type can only be “one or the other”
When we not only define the type of the parameter, but also if the parameter is object, it is possible that two properties of object are in conflict and can only be “one or the other”.
interface IMyParams {
a: number;
b: number;
}
// If we need to define a parameter as an object and its attribute A or b must be passed one
function calc(params: IMyParams) :number{
if (params.a) {
console.log(params.a + 1);
} else {
console.log(params.b + 1); }}Copy the code
The following defines an EitherOr type to handle this situation:
type FilterOptional<T> = Pick<
T,
Exclude<
{
[K in keyof T]: T extends Record<K, T[K]> ? K : never;
}[keyof T],
undefined
>
>;
type FilterNotOptional<T> = Pick<
T,
Exclude<
{
[K in keyof T]: T extends Record<K, T[K]> ? never : K;
}[keyof T],
undefined
>
>;
type PartialEither<T, K extends keyof any> = { [P inExclude<keyof FilterOptional<T>, K>]-? : T[P] } & { [PinExclude<keyof FilterNotOptional<T>, K>]? : T[P] } & { [PinExtract<keyof T, K>]? :undefined };
type Object = {
[name: string] :any;
};
export type EitherOr<O extends Object, L extends string, R extends string> =
(
PartialEither<Pick<O, L | R>, L> |
PartialEither<Pick<O, L | R>, R>
) & Omit<O, L | R>;
Copy the code
Use examples:
// Either a or B must be passed
type RequireOne = EitherOr<
{
a: number;
b: string;
},
'a'.'b'
>;
// Choose a or B, or neither
typeRequireOneOrEmpty = EitherOr< { a? :number; b? :string;
},
'a'.'b'
>;
Copy the code
Practical application:
interface IColumn {
title: string;
dataIndex: string;
render: () = > React.ReactNode;
}
// Those familiar with ANTD should know that the other dataIndex is meaningless if render is passed
// To put it another way, they are "either" attributes
interface ITableProps {
columns: Array<
EitherOr<
IColumn,
'dataIndex'.'render'
>
>;
}
function Table(props: ITableProps){
// TODO
}
Copy the code