dave-wind / blog

native javascript blog
0 stars 0 forks source link

Typescript 知识点 #11

Open dave-wind opened 1 year ago

dave-wind commented 1 year ago

在线ts解析工具: https://www.typescriptlang.org/play?ts=3.8.3

泛型

泛型是来作用类型的特殊变量,让类型泛化 他可以捕获用户提供的类型,返回的类型

function identity(arg: T): T { return arg; }

// 泛型 自动 类型推断 identity('sth') identity('sth')

// 加个length

function identity2(arg: T[]): number { console.log(arg.length) return arg.length }

// 赋值变量1 const demo: (arg: T[]) => number = identity2

// 赋值变量2 const demo2: { (arg: T[]): number } = identity2

// 赋值变量3 const demo3 = identity2

// 接口

interface GenericIdentityFn {

(arg: Type): Type; } let myIdentity: GenericIdentityFn = identity; // 类型约束 同样是 length interface Lengthwise { length: number; } function identity3(arg: T): T { console.log(arg.length); return arg } // identity3(3) 会报错 因为泛型函数现在受到约束,它将不再适用于任何和所有类型 identity3({ length: 10, value: 3 }); // ! 在泛型约束中使用类型参数; 意思就是 另一个key 用泛型约束去约束;俩类型用一个约束 // 想确保我们不会意外抓取 obj 上不存在的属性,因此我们将在这两种类型之间放置一个约束 function getProperty(obj: T, key: K) { return obj[key] } // 使用泛型创建工厂时,需要通过其构造函数引用类类型 function create(c: { new(): T }): T { return new c() } //eg: 一个更高级的示例使用原型属性来推断和约束构造函数和类类型的实例端之间的关系。 class ZooKeeper { nametag: string = "Mikle"; } class Animal { numLegs: number = 4; } class Lion extends Animal { keeper: ZooKeeper = new ZooKeeper() } function createInstance(c: { new(): A }): A { return new c } // 传Lion 类 第一步:返回Lion实例 createInstance(Lion).keeper.nametag; // Mikle // Lion 也是继承 Animal的 console.log(createInstance(Lion).numLegs) // 4 ``` ### 函数重载 Function overload > 编写重载签名来指定一个以不同方式调用的函数 (主要是参数不同 + 返回值不同) ```ts // 通常是一个或俩个,然后是 函数主体 eg: function makeDate(timestamp: number):Date function makeDate(m: number, d: number, y: number): Date; // 函数主体 function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { if (d !== undefined && y !== undefined) { return new Date(y, mOrTimestamp, d); } else { return new Date(mOrTimestamp); } } const d1 = makeDate(12345678); const d2 = makeDate(5, 5, 5); const d3 = makeDate(1, 3); // 报错, 参数一个或者3个 不可以俩个 ts 转为 js: function makeDate(mOrTimestamp, d, y) { if (d !== undefined && y !== undefined) { return new Date(y, mOrTimestamp, d); } else { return new Date(mOrTimestamp); } } ``` ### 最佳实战 ahooks > useToggle 例子 ```ts // 泛型接口 export interface Actions { setLeft: () => void; setRight: () => void; set: (value: T) => void; toggle: () => void; } // 函数重载 当参数为boolean 返回数组 第一个boolean 第二个对象 function useToggle(): [boolean, Actions]; function useToggle(defaultValue: T): [T, Actions]; // 表示 俩参数类型 T和U; defaultValue 默认是T, 返回值是T或者U , 第二个对象 function useToggle(defaultValue: T, reverseValue: U): [T | U, Actions]; // 函数主体定义 // 俩泛型参数 默认false reverseValue:反转值 // D=false as unknown as D: 又叫双重断言, D泛型 类型默认值是false unknown && D。可以是这俩类型 // 出自: https://stackoverflow.com/questions/69399211/typescript-why-does-as-unknown-as-x-work function useToggle(defaultValue:D=false as unknown as D,reverseValue?: R) { const [state, setState] = useState(defaultValue); // 做了缓存 const actions = useMemo(() => { const reverseValueOrigin = (reverseValue === undefined ? !defaultValue : reverseValue) as D | R; const toggle = () => setState((s) => (s === defaultValue ? reverseValueOrigin : defaultValue)); const set = (value: D | R) => setState(value); const setLeft = () => setState(defaultValue); const setRight = () => setState(reverseValueOrigin); return { toggle, set, setLeft, setRight, }; // useToggle ignore value change // }, [defaultValue, reverseValue]); }, []); return [state, actions]; } 如上代码 通过在线解析为js: // 就很明显了 😂 import { useMemo, useState } from react; function useToggle(defaultValue = false, reverseValue) { const [state, setState] = useState(defaultValue); const actions = useMemo(() => { const reverseValueOrigin = (reverseValue === undefined ? !defaultValue : reverseValue); const toggle = () => setState((s) => (s === defaultValue ? reverseValueOrigin : defaultValue)); const set = (value) => setState(value); const setLeft = () => setState(defaultValue); const setRight = () => setState(reverseValueOrigin); return { toggle, set, setLeft, setRight, }; // useToggle ignore value change // }, [defaultValue, reverseValue]); }, []); return [state, actions]; ``` ### 函数重载 demo ```ts function getInfo(name: string): string function getInfo(name: string, age: number): string function getInfo(name: string, age?: number) { return name + age } function info(name: T): String function info(name: T, age?: U): String function info(name: T = 'dave' as unknown as T, age?: U) { if (age) { return '' + age + name } if (name) { return name } return '' } ```
dave-wind commented 1 year ago

抽象类

抽象类 一般用作于 抽象类的属性和方法 只能用作于继承 去限制子类; 不用用于new; 用关键字 abstract 实现


abstract class Student {
private name: string // 保护的属性 一般只能在内部使用 子类不可使用
private age: number
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public get getName(): string {
return this.name
}
}

class ManStudent extends Student { constructor(name: string, age: number) { super(name, age) } }

dave-wind commented 1 year ago

Partial

Partial 是一个工具类型,它的作用是将某个接口的所有属性变为可选。这在我们需要实现一个接口的部分属性更新时非常有用


1.为什么要使用 Partial? 因为要申明一个新的类型时候,我有100个属性,通过Partial 变成可选,赋值的时候不需要100属性全部赋值
// 定义一个接口
interface Person {
name: string;
age: number;
address: string;
}
type PartialPerson = Partial<Person>

// 创建一个实现 PartialPerson 的对象 const partialPerson: PartialPerson = { name: "John", }; // 更新一个 Person 对象的部分属性 function updatePerson(person: Person, partialPerson: PartialPerson): Person { return { ...person, ...partialPerson }; }

const person: Person = { name: "Jane", age: 30, address: "123 Main St", };

const updatedPerson = updatePerson(person, partialPerson); console.log(updatedPerson); // 输出: { name: 'John', age: 30, address: '123 Main St' }

dave-wind commented 1 year ago

Omit

它可以从一个接口或类型中移除指定的属性,返回一个新的类型


语法:
type NewType = Omit<OriginalType, 'Property1' | 'Property2'>
栗子:
interface User {
id: number;
name: string;
age: number;
email: string;
}
现在我们想从 User 类型中移除 email 属性,可以使用 Omit 工具类型:
type UserWithoutEmail = Omit<User, 'email'>;

interface UserWithoutEmail { id: number; name: string; age: number; } 使用场景:

  1. 移除某些属性,以生成新的类型。
  2. 避免某些属性被修改或访问。

含义:

Omit 类型本质上是一个新的类型,它从原始类型中移除了指定的属性,并返回一个新的类型。这个新类型可以被用来代替原始类型,以实现更灵活的数据结构。

dave-wind commented 1 year ago

Pick

从某个类型中选取指定属性组成一个新的类型


interface PersonNameAndAge {
name: string;
age: number;
}
ype PersonNameAndAge = Pick<Person, 'name' | 'age'>;

// 等价于

interface PersonNameAndAge { name: string; age: number; } 使用场景:当我们需要从一个大型的对象中选取部分属性时,可以使用 Pick 来定义。

dave-wind commented 1 year ago

Record

根据一个键类型和一个值类型,创建一个新的类型,该类型的键为键类型,值为值类型。


type Weekday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday';
type WorkHours = Record<Weekday, string>;
// 等价于

interface WorkHours { Monday: string; Tuesday: string; Wednesday: string; Thursday: string; Friday: string; } 使用场景:当我们需要创建一个从键到值的映射时,可以使用 Record 来定义。