在看 Element plus 源码过程中看到如下代码:
export type NativePropType = | ((...args: any) => any) | { new (...args: any): any } | undefined | null
export type IfNativePropType<T, Y, N> = [T] extends [NativePropType] ? Y : N
这个代码产生两个疑问
((...args: any) => any) 是不是多了一个 |?
export type NativePropType = | ((...args: any) => any) | { new (...args: any): any } | undefined | null
在 TypeScript 中,| 是用来分隔不同的类型选项的,但在联合类型中,第一个类型选项前是否加 | 是没有问题的。这是因为 TypeScript 解析器对这种语法进行了处理,而且它不会影响类型的正确性。
所以,下面两种写法是等效的:
export type NativePropType =
((...args: any) => any)
| { new (...args: any): any }
| undefined
| null;
和
export type NativePropType =
| ((...args: any) => any)
| { new (...args: any): any }
| undefined
| null;
在第一个类型选项前加或者不加 | 都是允许的,而 TypeScript 会正确解析这个联合类型。这只是 TypeScript 对语法的一种宽容,不会影响类型定义的准确性。
export type IfNativePropType<T, Y, N> = [T] extends [NativePropType] ? Y : N 这个 [] 有什么作用?
这里 [T] 是为了确保 TypeScript 将 T 视为一个整体,而不是一个裸类型。在这个具体的条件类型中,如果省略 [T],它仍然会正常工作,因为 TypeScript 会正确地对 T 进行类型检查。
typescriptCopy codeexport type IfNativePropType<T, Y, N> = T extends NativePropType ? Y : N;
和
typescriptCopy codeexport type IfNativePropType<T, Y, N> = [T] extends [NativePropType] ? Y : N;
这里的 IfNativePropType 条件类型表示如果 T 是 NativePropType 的子类型,则返回 Y,否则返回 N。而 [T] 或者不加 [T] 对这个条件类型的实现没有影响。
当在条件类型中使用泛型参数时,加上 [T] 可以帮助确保 TypeScript 将泛型参数视为一个整体。这在某些情况下可能对类型推断更友好,特别是当泛型参数是一个联合类型时。
让我们看一个例子:
typescriptCopy codetype ExampleA<T> = T extends string ? "String Type" : "Non-String Type";
type ExampleB<T> = [T] extends [string] ? "String Type" : "Non-String Type";
const resultA: ExampleA<string | number> = "String Type";
const resultB: ExampleB<string | number> = "Non-String Type";
在这个例子中,ExampleA 和 ExampleB 是两个条件类型,用于判断泛型参数 T 是否是 string 类型。ExampleA 中没有使用 [T],而 ExampleB 中使用了 [T]。
结果是 resultA 的类型为 "String Type",而 resultB 的类型为 "Non-String Type"。
虽然在这个简单的例子中两者效果相同,但在更复杂的场景中,使用 [T] 可能对 TypeScript 的类型推断更友好,尤其是涉及联合类型时。