當(dāng)我們不單單要明確定義參數(shù)的類型侧馅,而且如果參數(shù)為 object
的話,還有可能出現(xiàn) object
里面某兩個(gè)屬性是沖突算谈,只能“二選一”的情況
interface IMyParams {
a: number;
b: number;
}
// 如果我們需要將一個(gè)參數(shù)定義為對(duì)象,并且其屬性 a 或者 b 必須要傳遞一個(gè)的話
function Table(params: IMyParams): number{
if (params.a) {
console.log(params.a + 1);
} else {
console.log(params.b + 1);
}
}
下面定義了一個(gè) EitherOr
的類型來(lái)處理這種情況:
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 in Exclude<keyof FilterOptional<T>, K>]-?: T[P] } &
{ [P in Exclude<keyof FilterNotOptional<T>, K>]?: T[P] } &
{ [P in Extract<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>;
使用例子:
// a、b二選一惫撰,并且必須傳遞一個(gè)
type RequireOne = EitherOr<
{
a: number;
b: string;
},
'a',
'b'
>;
// a、b二選一躺涝,或者都不傳
type RequireOneOrEmpty = EitherOr<
{
a?: number;
b?: string;
},
'a',
'b'
>;
實(shí)際應(yīng)用:
interface IColumn {
title: string;
dataIndex: string;
render: () => React.ReactNode;
}
// 熟悉 antd 的同學(xué)應(yīng)該都知道厨钻,如果傳遞了 render 的話,其他 dataIndex 其實(shí)就沒(méi)意義
// 換個(gè)角度來(lái)說(shuō)坚嗜,其實(shí)它們兩個(gè)是“二選一”的屬性
interface ITableProps {
columns: Array<
EitherOr<
IColumn,
'dataIndex',
'render'
>
>;
}
function Table(props: ITableProps){
// TODO
}