type
定义类型函数使用type
+泛型,可以定义类型函数:
type foo = T;
type bar = foo
可以对泛型入参进行约束、设置默认值
// 对入参进行约束
type foo = T;
type bar = foo
// 设定默认值
type foo = T;
type bar = foo
TypeScript中使用extends
进行类型判断,与三元运算符很相似:
T extends U ? X : Y;
如果T
的类型能够extends U
,结果返回X
,否则返回Y
。
结合上面的类型函数,可以进行扩展:
type num = 1;
type str = 'hello world';
type IsNumber = N extends number ? 'yes is a number' : 'no not a number';
type result1 = IsNumber; // 类型为 'yes is a number'
type result2 = IsNumber // 类型为 'no not a number'
使用in
关键在来遍历type
的联合类型
联合类型就是使用
|
来定义的类型的合集
type Key = 'vue' | 'react';
type Mapped = {[k in Key]: string}; // {vue: string; react: string}
const bar: Mapped = {
vue: 's',
react: 's'
}
如果联合类型不是我们显式的定义出来的,那么想要动态的推导出联合类型的类型,需要使用keyof
方法
interface Person {
name: string;
age: number;
}
type Foo = keyof Person; // 'name' | 'age'
map
操作可以使用extends
+泛型,实现将一组联合类型批量映射为另一种类型:
type Foo = 'a' | 'b';
type UnionTypesMap = U;
type Bar = UnionTypesMap
使用declare
关键字来声明全局作用域:
declare module '*.png';
declare module '*.svg';
declare module '*.jpg';
declare type str = string;
declare interface Foo {
propA: string;
propB: number;
}
要注意,如果模块使用了export
关键字导出了内容,上述方式可能会失效,需要显式的声明到全局:
declare global {
const ModuleGlobalFoo: string;
}
注意,上述方式之恩能够用在模块声明内,也就是说代码中必须包含export
,否则就会报错:
TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.
模块作用域的触发条件之一就是使用export
关键字导出内容,在其他模块获取时需要import
导入
never
类型的作用never
类型代表空集,常用语校验“类型收窄”是否符合预期,常被用来做“类型收底”。
例如,有一个联合类型时:
interface Foo {
type: 'foo'
}
interface Bar {
type: 'bar'
}
type All = Foo | Bar
在switch
判断type
,TS是可以收窄类型的(discriminated union):
funcfunction handleValue(val: All) {
switch (val.type) {
case 'foo':
// 这里 val 被收窄为 Foo
break
case 'bar':
// val 在这里是 Bar
break
default:
// val 在这里是 never
const exhaustiveCheck: never = val
break
}
}
在default
里面把收窄的never
的val
赋给了显示声明为never
的变量。如果有一天type
类型被修改了:
type All = Foo | Bar | Baz
如果没有在handleValue
添加针对Baz
的处理逻辑,这时候在default
的分支中就会编译错误。所以通过这个办法可以确保switch
总是穷尽了所有All
的可能性
never
进行类型过滤联合类型当never
参与运算时T | never
的结果是T
,根据这个规则就可以过滤联合类型中不符合期望的类型,TS内置的Exclude
泛型操作符就是根据这个原理实现的:
/**
* Exclude from T those types that are assignable to U
*/
type Exclude = T extends U ? never : T;
type A = 1 | 2;
type B = Exclude; // 2
类型守卫(Type Guard)的目的就是为了对类型进行分流,将联合类型分发到不同管道。可以出发类型守卫的常见方式有:typeof
、instancof
、in
、==
、===
、!=
、!==
等
function foo(x: A | B) {
if (x instanceof A) {
// x is A
} else {
// x is B
}
}
当以上的方式不满足需求时,可以通过is
关键字自定义类型守卫:
function isA(x): x is number {
return true
}
function foo(x: unknown) {
if(isA(x)) {
return x
}
return null;
}