基础的泛型声明
function identity<Type>(arg: Type): Type {
return arg;
}
var test = identity({
name: 'tom',
age: 18
});
test.name; // string
test.age; // number
var test2: string = identity('aa'); 正确
var test3: number = identity('aa'); //错误
实现vu3里钩子的函数类型定义
type Ref<T> = { value: T };
function ref<T>(params?: T): Ref<T | never> {
return {} as any;
}
function reactive<T>(params: T): T {
return {} as any;
}
const data = reactive({ name: 'tomg' });
data.name;
const $el = ref<{ name: string, age: 14 }>();
$el.value;
$el.value.age;
const $user = ref({ name: '111111', age: 1 });
$user.value.name;
防止获取object时候输入错误key
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x = { a: 1, b: '2', c: 3, d: 4 };
getProperty(x, 'b'); // 正确使用
getProperty(x, 'e'); // 会提示值不存在
前置不定量参数
type JSTypes = 'string' | 'function' | 'number' | 'symbol' | 'object' | 'undefined' | 'boolean' | 'bigint'
type JSTypeMap = {
'string': string
'function': Function,
'number': number,
'symbol': Symbol,
'object': Object,
'undefined': undefined,
'boolean': 'boolean',
'bigint': BigInt
}
type ArgsType<T extends JSTypes[]> = {
[key in keyof T]: JSTypeMap[T[key]]
}
declare function addImpl<T extends JSTypes[]>(...args: [
...T,
(...args: ArgsType<T>) => void
]) : void;
addImpl('string', 'number', function(a, b) {
})
创建new Class
function create<Type, Param>(c: { new (...argv: Param[]): Type }, argv: Param[]): Type {
return new c(...argv);
}
class Test {
name: string = '';
}
var $test: Test = create(Test);
$test.name;
模板字符串类型
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
type Lang = "en" | "ja" | "pt";
type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`;
基础映射类型
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
映射修饰符
添加-
或前缀来删除或添加这些修饰符+
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property];
};
type LockedAccount = {
readonly id: string;
readonly name: string;
};
type UnlockedAccount = CreateMutable<LockedAccount>;
-----
// 通过-?,删除修饰符,使所有字段都必须有
type Concrete<Type> = {
[Property in keyof Type]-?: Type[Property];
};
type MaybeUser = {
id: string;
name?: string;
age?: number;
};
type User = Concrete<MaybeUser>;
键重映射通过类型
type Getters<Type> = {
[Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
interface Person {
name: string;
age: number;
location: string;
}
type LazyPerson = Getters<Person>;
// 通过Getters输出的类型
type LazyPerson = {
getName: () => string;
getAge: () => number;
getLocation: () => string;
}
// ------
//`never`通过条件类型生成来过滤键
type RemoveKindField<Type> = {
[Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};
interface Circle {
kind: "circle";
radius: number;
}
type KindlessCircle = RemoveKindField<Circle>;
// 通过RemoveKindField输出的类型
type KindlessCircle = {
radius: number;
}
练习
type CreateClassProperty<Type> = {
[Property in keyof Type as `$${string & Property}Change`]: (
fn: (value: Type[Property]) => void
) => void
} & {
[Property in keyof Type as `set${Capitalize<string & Property>}`]: (value: Type[Property]) => void
} & Readonly<Type>
function çreateClass<T>(props: T): CreateClassProperty<T> {
// ... 忽略拓展逻辑
return props as any
}
const user = çreateClass({
name: 'tom',
age: 14
})
user.$nameChange(name => console.log(name));
user.$ageChange(age => console.log(age));
user.setAge(123);
user.age
根据输入值判断获取类型返回值
interface IdLabel {
id: number /* some fields */;
}
interface NameLabel {
name: string /* other fields */;
}
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel;
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
throw "unimplemented";
}
let a: NameLabel = createLabel("typescript");
let b: IdLabel = createLabel(666);
多类型合并
type AllKeys<T> = T extends any ? keyof T : never
type PickType<T, K extends AllKeys<T>> = T extends { [k in K]: any }
? T[K]
: undefined
type PickTypeOf<T, K extends string | number | symbol> = K extends AllKeys<T>
? PickType<T, K>
: never
type Merge<T extends object> = {
[k in AllKeys<T>]: PickTypeOf<T, k>
}
// 演示
// error: 类型 "{ name: string; }" 中缺少属性 "age",但类型 "Merge<{ name: string; } | { age: number; }>" 中需要该属性。
const ok: Merge<{name:string} | {age: number}> = {
name: '',
}
// success
const ok: Merge<{name:string} | {age: number}> = {
name: '',
age: 14
}
多类继承
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Constructor<T = {}> = new (...args: any[]) => T;
function Extend<T extends Constructor[]>(...classList: T): Constructor<UnionToIntersection<InstanceType<T[number]>>> {
let Class = class {};
classList.forEach(fn => {
Class = class extends fn {
constructor(...argv: any[]) {
super(...argv);
}
}
})
return Class as any;
}
class Name {
constructor(name: string) { }
getName() {
}
}
class Age {
constructor(age: number) { }
sx = 'tom';
/**获取年龄 */
getAge() {
return this.sx
}
}
class People extends Extend4(Name, Age) {
dq() {
return 'dq'
}
}
const zs = new People();
zs.getName;
zs.getAge;
zs.sx;
console.log(zs, zs.sx, zs.getAge(), zs.dq())
条件类型约束
type MessageOf<T extends { message: unknown }> = T["message"];
interface Email {
message: string;
}
type EmailMessageContents = MessageOf<Email>;
----------------
// 设置如果不存在就换成其他类型
type MessageOf2<T> = T extends { message: unknown } ? T["message"] : string;
interface Dog {
bark(): void;
}
type DogMessageContents = MessageOf2<Dog>;
// DogMessageContents: string
分配条件类型
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>;
// StrArrOrNumArr类型是: string[] | number[]
// 通常,分配性是所需的行为。为避免这种行为,您可以`extends`用方括号将关键字的每一侧括起来
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
type StrOrNumArr = ToArrayNonDist<string | number>;
// 此时StrOrNumArr类型就变成了(string | number)[]
将object内具体的值声明为类型
const People = [
{ name: '张三', age: 18 },
{ name: '李四', age: 32 },
{ name: '王五', age: 24 }
] as const;
type PeopleName = {
readonly [key in typeof People[number]['name']]: string;
};
type PeopleAge = {
readonly [key in typeof People[number]['age']]: number;
};
type PeopleNameValue = typeof People[number]['name'];
// PeopleNameValue类型为"张三" | "李四" | "王五"
type PeopleAgeValue = typeof People[number]['age'];
// PeopleAgeValue类型为18 | 32 | 24
修改object 的this执行,实现vue结构的this执行
type PageType<D, M> = {
data: D;
methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
}
function Page<D,M>(param: PageType<D, M>): D & M {
let data: object = param.data || {};
let methods: object = param.methods || {};
return { ...data, ...methods } as D & M;
}
Page({
data: {
name: '张三',
age: 14
},
methods: {
say() {
this.name;
}
}
})
实现类似react ui库material-ui中makeStyles的类型声明
/**
* 简单的定义css类型
* 项目中使用建议换成csstype
* @link https://www.npmjs.com/package/csstype
*/
interface StyleAttribute {
width: string
height: string
}
type PropsFunc<Props extends object, T> = (props: Props) => T;
/**
* Partial是ts内置的类型转换,将所有必须的输入项换成不必须的,与之相反的是Required
* @link https://www.typescriptlang.org/docs/handbook/utility-types.html
*/
type StyleRules<Props extends object = {}, ClassKey extends string = string> = Record<
ClassKey,
Partial<StyleAttribute> | PropsFunc<Props, Partial<StyleAttribute>>
>
function maskStyle<
ClassKey extends string,
Props extends {}
>(params: StyleRules<Props, ClassKey>): StyleRules<Props, ClassKey> {
// 这里进行各种处理
return {} as any;
}
var styles = maskStyle({
name: { width: '' },
theme: () => {
return { width: '', height: '' }
}
})
继续上一个换成传入function方式定义
interface ThemeData {
width: string,
height: string
}
type MaskStyleFunction<ClassKey extends string, Props extends {}> = (param) => StyleRules<Props, ClassKey>
function maskStyle2<ClassKey extends string, Props extends {}>(style: MaskStyleFunction<ClassKey, Props>): () => Record<ClassKey, string> {
// 这里进行各种处理
return {} as any;
}
var useStyles = maskStyle2((theme: ThemeData) => {
return {
name: {
width: theme.width
},
theme: () => {
return { width: '', height: '' }
}
}
})
const styles = useStyles();
styles.name;
实用程序类型
/**
* 官方文档地址
* @link https://www.typescriptlang.org/docs/handbook/utility-types.html
*/
// 将全部变为可不填写
type Partial_Test = Partial<Todo>;
// 将全部变为必须填写
type Required_Test = Required<Todo>;
// 将全部变为只读
type Readonly_Test = Readonly<Todo>;
// 让第一个传入的值都变为第二个传入参数的类型
type Record_Test = Record<"first1"|"first2", Todo>;
// 在第一个值中不包含第二个传入的字段全部删掉,组成新的类型
type Pick_Test = Pick<Todo, 'title' | 'completed'>;
// 与Omit相反,在第一个值中删除第二个参数包含的字段,组成新的类型
type Omit_Test = Omit<Todo, 'title'>;
// 排除第二个传值中包含的类型
type Exclude_Test = Exclude<"a" | "b" | "c", "a">
type Exclude2_Test = Exclude<string | number | (() => void), Function|number>;
// 与Exclude相反,返回第二个传值中包含的类型
type Extract_Test = Extract<"a" | "b" | "c", "b" | "c">;
// 去除类型中的null和undefined
type NonNullable_Test = NonNullable<string | null | undefined>;
// Parameters提取function的参数组成一个新的type
declare function f1(arg: { a: number; b: string }): Todo;
type Parameters_Test = Parameters<typeof f1>;
type Parameters_Test2 = Parameters<(s: string) => void>;
// ReturnType是获取function的返回值组成一个新的type
type ReturnType_Test = ReturnType<() => string>;
type ReturnType_Test1 = ReturnType<typeof f1>;
// ConstructorParameters用于获取构造函数内的值并生成一个新的type
class TestConstructorParameters { constructor(name: string,age: number) {} }
type ConstructorParameters_Test = ConstructorParameters<typeof TestConstructorParameters>;
type InstanceType_tset = InstanceType<typeof TestConstructorParameters>;
// ThisParameterType用于提取function的this类型,如果没有则用位置this
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}
// OmitThisParameter不太明白,可以具体查看文档
// ThisType在上述的【修改object 的this执行,实现vue结构的this执行】中也有相关代码
// 充当上下文this类型的标记
const stringValue = 'adAwdcawd';
// 将字符串转为大写
type Uppercase_test = Uppercase<typeof stringValue>;
// 将字符串转为小写
type Lowercase_test = Lowercase<typeof stringValue>;
// 将首字母转为大写
type Capitalize_test = Capitalize<typeof stringValue>;
// 将首字母转为小写
type Uncapitalize_test = Uncapitalize<"AcfCff">;
// 获取promise的返回值类型,4.5版本新增
type A = Awaited<Promise<string>>;
在Function上创建静态属性和方法
interface jQuery {
(): void;
ajax: (config: any) => void
get: (config: any) => void
}
const jQuery: jQuery = () => {
}
jQuery.ajax = (data: any) => {
}
jQuery.get = (data: any) => {
}
只做参考学习使用