TS(TypeScript)基础知识八:类型转换(别名和函数)

2,682 阅读5分钟

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

别名中的类型转换

Exclude<Type, ExcludedUnion>

“排除”:通过从 Type 中排除所有可分配给 ExcludedUnion 的类型构造一个类型

例 :

type Attrs = 'height' | 'width' | 'border' | (() => void)
type SomeAtts = Exclude<Attrs, 'border' | Function>

let a: SomeAtts = 'height'

解析:从别名中 Attrs 中排除了‘border’和‘Function’构造出新的类型别名;

Extract<Type, Union>

“提取”:通过从 Type 中提取可以分配给 Union 的所有类型来构造类型

例 :

type attrs = 'height' | 'width' | 'border' | (() => void)
type SomeAtts = Extract<attrs, 'font' | Function>

a = function name( ) { }

解析:attrs中可以分配给Union的类型只有Function;新的类型SomeAttrs实际被转换为type SomeAttrs = Function 。Extract实际上就是获取两者的交集构造新的类型。

上面的两个例子中提到的 Function 和 (() => void) 都表示方法、函数

NonNullable

通过从 Type 中排除 null 和 undefined 来构造一个类型

type attrs = 'height' | 'width' | (() => void) | null | undefined
type SomeAtts = NonNullable<attrs>

解析:新别名SomeAtts中不包含 undefined 和 null

函数中的类型转换

Parameter

“参数”:从函数类型 Type 的参数中使用的类型构造元组类型(提取函数中的参数类型,构造成一个数组类型)

例子一

type Case = Parameters<() => string>;
// type Case = []
let a: Case = []

解析: 将一个参数为空返回值为string的函数类型转换为一个空数组类型。

例子二

type Case = Parameters<(s: string) => void>;
// type Case  = [s: string]
let b: Case = ['sdf']

解析: 将一个参数为一个字符串类型返回值为void的函数类型转换为只有一个字符串项的数组类型

例子三

type Case1 = Parameters<<T>(arg: T) => T>;
// type Case1 = [arg: unknown]

type Case2 = Parameters<any>;
// type Case2 = unknown[]     
let d: Case1 = ['']
let c: Case2 = [1, 2, 3]

解析: 上面的Case1 和 Case2 都是转换为未知的数组类型。
但是 Case1 是转换为长度为一的元素类型未知的数组类型。
Case2 是转换为 长度未知,元素类型未知的未知数组类型;

例子四

type Case5 = Parameters<never>;
// type Case5 = never

解析: 转换为 never 类型

错误例子

type Case6 = Parameters<string>;
// type Case6 = never
type Case7 = Parameters<Function>;
// type Case7 = never

//Error: Caseype 'string' does not satisfy the constraint '(...args: any) => any'.

//Error: Caseype 'Function' does not satisfy the constraint '(...args: any) => any'.

解析: 如果强制转换,那么转换结果也是 never 类型;

ReturnType

“返回类型”:构造一个由 Type 函数的返回值类型组成的新类型。

例一

type Case = ReturnType<() => string>;
// type Case = string
type Case2 = ReturnType<<T>() => T>;
// type Case2 = unknown

解析: 将原类型转换为返回值的类型(即为string类型);当返回值为未知类型时,转换为未知类型;

例二

type T3 = ReturnType<<T extends U, U extends number[]>() => T>;
// type T3 = number[]

解析: T继承自U,U继承自数字类型数组,所以T为数字number类型数组的子集。依然属于number数组类型。

例三

declare function f1(): { a: number; b: string };
type T4 = ReturnType<typeof f1>;
// type T4 = {
//     a: number;
//     b: string;
// }

解析: 声明了函数f1,函数返回值为一个包含两个键值对的对象。返回值的类型为新的类型。

例四

type T5 = ReturnType<any>;
// type T5 = any

解析: 任意any类型

例五

type T6 = ReturnType<never>;
// type T6 = never

解析: never类型

错误例子

type T7 = ReturnType<string>;
// type T7 = any

type T8 = ReturnType<Function>;    
// type T8 = any

Error: Type 'string' does not satisfy the constraint '(...args: any) => any'.
Error: Type 'Function' does not satisfy the constraint '(...args: any) => any'.
Error: Type 'Function' provides no match for the signature '(...args: any): any'.

解析: 和Parameters方法类似,没有返回值报错;强制转换的结果为any;

ThisParameterType

提取函数类型的 this 参数的类型,如果函数类型没有 this 参数,则未知。

declare function fn(): { a: number; b: string };
type F = ThisParameterType<typeof fn>
// type F = unknown  

function fn2(this: number) { }
type F2 = ThisParameterType<typeof fn2>
// type F2 = number

解析: this必须要在参数中指明类型,才可以提取。提取后构造为新的类型。

OmitThisParameter

// 从 Type 中删除 this 参数,创建一个没有this参数的新函数类型。 如果 Type 没有显式声明this参数,则不对 Type 进行处理。

function fn(this: number): number{ return this }
type F = OmitThisParameter<typeof fn>
// type F = () => number

ThisType

此实用程序不返回转换后的类型。相反,它充当上下文这种类型的标记。请注意,必须启用 --noImplicitThis 标志才能使用此实用程序。

type ObjectDescriptor<D, M> = {
    data?: D;
    methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
    let data: object = desc.data || {};
    let methods: object = desc.methods || {};
    return { ...data, ...methods } as D & M;
}

let obj = makeObject({
    data: { x: 0, y: 0 },
    methods: {
        moveBy(dx: number, dy: number) {
            this.x += dx; // Strongly typed this
            this.y += dy; // Strongly typed this
        },
    },
});

obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);

翻译:

在上面的例子中,makeObject 参数中的方法对象有一个上下文类型,包括 ThisType<D & M> 因此方法对象中方法中的 this 类型是 { x: number, y: number } & { moveBy (dx: number, dy: number): number }. 请注意,methods 属性的类型如何同时是方法中此类型的推理目标和源。 ThisType 标记接口只是一个在 lib.d.ts 中声明的空接口。除了在对象字面量的上下文类型中被识别之外,该接口的作用类似于任何空接口。

ConstructorParameters

从构造函数类型的类型构造元组或数组类型。它生成一个包含所有参数类型的元组类型(或者如果 Type 不是函数,则类型 never )

type T0 = ConstructorParameters<ErrorConstructor>;
     
// type T0 = [message?: string]
type T1 = ConstructorParameters<FunctionConstructor>;
     
// type T1 = string[]
type T2 = ConstructorParameters<RegExpConstructor>;
     
// type T2 = [pattern: string | RegExp, flags?: string]
type T3 = ConstructorParameters<any>;
// type T3 = unknown[]

InstanceType

构造一个由 Type 中构造函数的实例类型组成的类型

class C {
    x = 0;
    y = 0;
}

type T = InstanceType<typeof C>;
let a: T = {
    x: 1,
    y: 2
}

解析: 将类C实例后转化为新的类型;

字符串中的类型转换

Uppercase

type T = Uppercase<'string'>;
let a: T =  'STRING'

解析: 字符串转换为大写;

Lowercase

type T2 = Lowercase<'STRING'>;
let a2: T2 =  'string'

解析: 字符串转换为小写;

Capitalize

type T3 = Capitalize<'string'>;
let a3: T3 =  'String'

解析: 字符串首字母转换为大写;

Uncapitalize

type T4 = Uncapitalize<'STRING'>;
let a4: T4 =  'sTRING'

解析: 字符串首字母转换为小写;

至此关于类型转换方面的介绍就结束了。如果没有意外短期内不会再有关于TS的分享。不过我会抽出时间整合目前所分享的内容,并且做一些拓展和更详细的说明。致谢!