精华内容
下载资源
问答
  • Ts修饰符

    2020-01-30 20:39:49
    TypeScript修饰符

    TypeScript修饰符
    在这里插入图片描述

    展开全文
  • 下面分别介绍一下类的访问修饰符:一.public访问修饰符:在TypeScript中,成员都默认为public(在C#等语言则需要显式的规定);可以省略。代码实例如下:class Antzone {public webName: string;public constructor...

    关于类的基本用法,可以参阅TypeScript class 类介绍一章节。

    下面分别介绍一下类的访问修饰符:

    一.public访问修饰符:

    在TypeScript中,成员都默认为public(在C#等语言则需要显式的规定);可以省略。

    代码实例如下:class Antzone {

    public webName: string;

    public constructor(webName: string) { this.webName = webName; }

    public show(age: number) {

    console.log(`${this.webName} 成立 ${age}年了.`);

    }

    }

    let antzone=new Antzone("Downzz.com");

    antzone.show(4);

    使用public修饰的成员,可以在类的内外自由访问。

    二.private修饰符:

    当成员被标记成private时,就不能在声明它的类的外部访问。

    代码实例如下:class Antzone {

    private webName: string;

    public constructor(webName: string) { this.webName = webName; }

    public show(age: number) {

    console.log(`${this.webName} 成立 ${age}年了.`);

    }

    }

    let antzone=new Antzone("Downzz.com");

    antzone.webName;

    由于webName是私有类型,所以会报错,截图如下:

    三.protected访问修饰符:

    protected与private行为相似,但有一点不同,protected成员在派生类中可以访问。

    代码实例如下:class Person {

    protected name: string;

    constructor(name: string) { this.name = name; }

    }

    class Employee extends Person {

    private department: string;

    constructor(name: string, department: string) {

    super(name)

    this.department = department;

    }

    public getElevatorPitch() {

    return `Hello, my name is ${this.name} and I work in ${this.department}.`;

    }

    }

    let howard = new Employee("Howard", "Sales");

    console.log(howard.getElevatorPitch());

    console.log(howard.name);

    由于父类中的name访问修饰符是protected,所以可以在它的派生类中访问:public getElevatorPitch() {

    return `Hello, my name is ${this.name} and I work in ${this.department}.`;

    }

    所以上面的代码是正确的,但是不能够在类的外部访问:console.log(howard.name)

    所以上面的代码会报错,截图如下:

    四.readonly修饰符:

    使用readonly关键字将属性设置为只读的。

    只读属性必须在声明时或构造函数里被初始化,代码实例如下:class Antzone {

    readonly webName: string;

    public constructor(webName: string) { this.webName = webName; }

    public show(age: number) {

    console.log(`${this.webName} 成立 ${age}年了.`);

    }

    }

    let antzone=new Antzone("Downzz.com");

    antzone.webName="蚂蚁奋斗";

    由于webName是只读的,所以在非声明或者构造函数里给它赋值会报错。

    展开全文
  • 4.0 新特性:可变元组类型ts4 在 ts3 元组类型的基础上扩充了三点功能:1.支持 spread 运算符在元组类型中作为泛型通过这种方式,开发者可以定义元素类型不确定的数组或元组,同时编译器也可以自动推断出数组或元组...

    距离 typescript4.x 版本发布已经有一段时间,目前最新版本为 4.1.3。相较于 3.x 版本,4.x 又支持哪些新特性呢?

    4.0 新特性:

    可变元组类型

    ts4 在 ts3 元组类型的基础上扩充了三点功能:

    1.支持 spread 运算符在元组类型中作为泛型

    通过这种方式,开发者可以定义元素类型不确定的数组或元组,同时编译器也可以自动推断出数组或元组的元素类型。

    function tail(arr: readonly [any, ...T]) {

    const [_ignored, ...rest] = arr;

    return rest;

    }

    const myTuple = [1, 2, 3, 4] as const;

    const myArray = ["hello", "world"];

    // type [2, 3, 4]const r1 = tail(myTuple);

    // type [2, 3, 4, ...string[]]const r2 = tail([...myTuple, ...myArray] as const);

    2.spread 扩展的 rest 类型不必放到最后定义

    ts4 中,可变元组类型不再要求 rest 类型放到最后定义。

    type Strings = [string, string];

    type Numbers = [number, number];

    // [string, string, number, number, boolean]type StrStrNumNumBool = [...Strings, ...Numbers, boolean];

    /*ts3 error 'A rest element must be last in a tuple type'!ts4 ok!*/

    结合以上两点,开发者将不再需要编写繁琐的重载定义,以 function concat(arr1, arr2) {return [...arr1, ...arr2]} 函数为例:

    在 ts3 中只能通过显示定义函数重载才能明确 concat 的返回值类型,无奈的是,这种做法无法罗列所有情况并不是一种通用实现。

    function concat(arr1: [], arr2: [A2]): [A2];

    function concat(arr1: [A1], arr2: [A2]): [A1, A2];

    function concat(arr1: [A1, B1], arr2: [A2]): [A1, B1, A2];

    function concat(arr1: [A1, B1, C1], arr2: [A2]): [A1, B1, C1, A2];

    function concat(arr1: [A1, B1, C1, D1], arr2: [A2]): [A1, B1, C1, D1, A2];

    function concat(arr1: [A1, B1, C1, D1, E1], arr2: [A2]): [A1, B1, C1, D1, E1, A2];

    function concat(arr1: [A1, B1, C1, D1, E1, F1], arr2: [A2]): [A1, B1, C1, D1, E1, F1, A2];

    更一般的做法是将 concat 定义为 function concat(arr1: T[], arr2: U[]): Array 但是对于编译器来说,它无法确认 concat 返回值数组长度和不同元素类型在数组中的位置。

    有了可变元组类型以后,开发者只需简单几个语句便可定义出覆盖所有情况的 concat 类型,并且编译器可以精确推断出返回值数组长度和元素类型在数组中的位置。

    type Arr = readonly any[];

    function concat(arr1: [...T], arr2: [...U]): [...T, ...U] {

    return [...arr1, ...arr2];

    }

    // type = [number, number, string, string]const arr = concat([1,2], ['hello', 'world'])

    元组标签

    ts4 带来的关于元组类型第三点变化是支持对元组类型打标签,类似于 js 中解构变量重命名。

    type Range = [start: number, end: number];

    type Foo = [first: number, second?: string, ...rest: any[]];

    type Bar = [first: string, number]; // error! Tuple members must all have names or all not have names.

    如果对元组类型打标签,则其中所有类型必须都标签化,不允许一部分类型标签化,一部分没有。

    元组标签主要用于定义函数的入参,通过元组标签,编译器可以更好的提示函数入参类型

    根据构造函数推断类属性类型

    ts4 之前,如果不显示定义类属性的类型,编译器就会默认推断类属性类型为 any,ts4 开始,编译器可以通过开发者在构造函数中的赋值行为推断类属性的类型,前提是开启 noImplicitAny 选项 。

    class Square {

    area; // number sideLength; // number

    constructor(sideLength: number) {

    this.sideLength = sideLength;

    this.area = sideLength ** 2;

    }

    }

    短路运算符

    在 +=,-=,*=,/= 等快捷运算式之外,ts4 还支持了 &&=,||=,??= 三个短路运算符,以 ||= 为例

    obj.prop ||= foo();

    // 等价于下面两种表达式 ,注意与 obj.prop = obj.prop || foo() 的区别 !!

    obj.prop || (obj.prop = foo());

    if (!obj.prop) {

    obj.prop = foo();

    }

    catch 错误允许置为 unknown

    在 ts4 之前,try/catch 捕获的异常被编译器视为 any 类型,然而 catch 内部的处理逻辑也可能产生非预期的错误,这就要求对 catch 捕获的异常有更严格的类型定义,ts4 允许将异常显示定义成 unknown 类型,开发者需进一步判断异常具体类型。

    try {

    // ...}

    catch (e: unknown) {

    // error! // Property 'toUpperCase' does not exist on type 'unknown'. console.log(e.toUpperCase());

    if (typeof e === "string") {

    // works! console.log(e.toUpperCase());

    }

    }

    自定义 JSX 工厂函数

    从 ts4 开始,通过新增的 jsxFragmentFactory 选项或内联的 @jsxFrag 注释,开发者可以自定义 jsx Fragment 语法的工厂函数, 如:

    {

    "compilerOptions": {

    "target": "esnext",

    "module": "commonjs",

    "jsx": "react",

    "jsxFactory": "h",

    "jsxFragmentFactory": "Fragment"

    }

    }

    /** @jsx h */

    /** @jsxFrag Fragment */

    import { h, Fragment } from "preact";

    let stuff = <>

    Hello

    >;

    /* 编译输出为import { h, Fragment } from "preact";let stuff = h(Fragment, null,h("div", null, "Hello"));*/

    其他新特性--incremental 和 --noEmitOnError 同时开启时,会自动缓存前一次编译的错误到 .tsbuildinfo 文件

    允许同时开启 --incremental 和 --noEmit

    vscode 支持将条件判断表达式转为可选链式操作符vscode 支持提示 /** @deprecated */ 注释

    vscode 支持对单份 ts 代码文件编译提速

    vscode 支持更智能的自动导入

    不兼容变化ts3 中当设置了 useDefineForClassFields 时,在继承类的过程中,不允许 getter/setter 属性和其他属性的互相覆盖,ts4 中不再需要设置 useDefineForClassFields,默认禁止互相覆盖

    被 delete 的对象属性必须是可选的

    ts4 前与 AST 节点相关的工厂函数被新的工厂函数所替代,老的完全被废弃

    参考资料Announcing TypeScript 4.0 | TypeScript​devblogs.microsoft.com

    -------------------------------------------------------------------------------------------

    4.1 新特性:

    模版字符串类型

    es6 后新增了模版字符串,用户可以通过向字符串注入变量的方式来构造新的变量,ts4 则可以通过向字符串注入类型的方式来构造新的类型。

    type World = "world";

    type Greeting = `hello${World}`;

    // same as// type Greeting = "hello world";

    模版字符串类型可以用于:

    1.简化复杂字符串类型的定义

    ts4 之后,开发者可以简化对复杂字符串类型的定义,事实上模版字符串类型起到了自动组合类型的效果。

    // ts3type Alignment = "top-left" | "top-center" | "top-right" | "middle-left" | "middle-center" | "middle-right"| "bottom-left" | "bottom-center" | "bottom-right"

    // ts4type VerticalAlignment = "top" | "middle" | "bottom";

    type HorizontalAlignment = "left" | "center" | "right";

    type Alignment = `${VerticalAlignment}-${HorizontalAlignment}`

    2.修改动态推导的的字符串类型

    假设我们想对某个对象的属性变化进行监听并且定义了一个 makeWatchedObject 方法来监听对象属性。

    let person = makeWatchedObject({

    firstName: "Homer",

    age: 42,

    location: "Springfield",

    });

    person.on("firstNameChanged", (newName) => {

    console.log(`firstName was changed to${newName}!`);

    });

    person.on("ageChanged", (newAge) => {

    console.log(`age was changed to${newAge}!`);

    });

    person.on("locationChanged", (newLocation) => {

    console.log(`location was changed to${newLocation}!`);

    });

    属性变化的事件名格式为 ${property}Changed,采用模版字符串类型定义 makeWatchedObject 类型:

    type PropEventSource = {

    on(eventName: `${string & keyof T}Changed`, callback: (v: any) => void): void;

    };

    declare function makeWatchedObject(obj: T): T & PropEventSource;

    更进一步,我们可以通过模版字符串类型来推导 callback: (v: any) => void 中 v的类型:

    type PropEventSource = {

    on

    (eventName: `${K}Changed`, callback: (v: T[K]) => void): void;

    };

    declare function makeWatchedObject(obj: T): T & PropEventSource;

    映射类型属性重映射

    在 ts4 之前的版本中,开发者可通过映射类型从旧类型中创建新类型,如常用 Partial 类型:

    type Partial = {

    [P in keyof T]?: T[P];

    }

    interface Props {

    name: string

    age: number

    }

    type NewProps = Partial

    映射类型最大的作用是将旧类型的每个属性按照相同的方式映射到新类型中,像 Partial 就是把所有属性都映射成可选,但是在 ts4 之前的版本对属性的转换方式仅仅局限在增加属性修饰符(readonly,? 等)上:

    type Readonly = {

    readonly [P in keyof T]: T[P];

    }

    type Partial = {

    [P in keyof T]?: T[P];

    }

    从 ts4 开始,将支持对属性更进一步的映射,开发者可以通过 as 保留字重新构造想要的属性。

    1.属性重命名

    type Getters = {

    [K in keyof T as `get${Capitalize}`]: () => T[K]

    };

    interface Props {

    name: string;

    age: number;

    location: string;

    }

    type NewProps = Getters;

    /* 等于interface NewProps {getName: () => string;getAge: () => number;getLocation: () => string;}*/

    2.去除属性

    type RemoveField = {

    [K in keyof T as Exclude]: T[K]

    };

    interface Props {

    foo: string;

    bar: number;

    }

    type NewProps = RemoveField;

    /* 等于type NewProps = {bar: number;};*/

    3.过滤属性

    type GetMethods = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };

    interface Props {

    foo(): number,

    bar: boolean

    }

    type NewProps = GetMethods;

    /* 等于type NewProps = {foo(): number;};*/

    4.衍生属性

    type DoubleProps = { [P in keyof T & string as `${P}1` | `${P}2`]: T[P] }

    interface Props {

    a: string,

    b: number

    }

    type NewProps = DoubleProps;

    /* 等于type NewProps = { a1: string, a2: string, b1: number, b2: number }*/

    递归条件类型

    ts3 支持通过特定条件判断来获取类型:

    type IsString = T extends string ? true : false;

    type A = IsString; // truetype B = IsString; // false

    为了更好的支持类型推断,ts4 在条件类型的基础上又增加了可递归的条件判断,常用递归条件类型模式为:type A = T extends B ? A : T

    比如常见的数组拍平函数 deepFlatten,假设其输入为任意嵌套的未知类型数组,对应的输出为推导的某类型数组,通过递归条件类型表达为:

    // 可递归条件类型type ElementType =

    T extends ReadonlyArray ? ElementType : T;

    function deepFlatten(x: T): ElementType[] {

    throw "not implemented";

    }

    // 全部返回 'number[]':deepFlatten([1, 2, 3]);

    deepFlatten([[1], [2, 3]]);

    deepFlatten([[1], [[2]], [[[3]]]]);

    再一个经典的例子便是推断 await 语句的返回值类型:

    type Awaited =

    T extends PromiseLike ? Awaited : T;

    type P1 = Awaited>; // stringtype P2 = Awaited>>; // stringtype P3 = Awaited | undefined>>; // string | number | undefined

    值得注意的是,递归条件类型虽然强大,但是会额外增加编译器在检查 ts 类型时的耗时,出于编译性能考虑,ts 编译器会对递归条件类型的层级有所限制,一旦超过了这个限制,在编译时就会报错,开发者在使用递归条件类型时也应该控制好输入的类型层级。

    其他新特性新增 --noUncheckedIndexedAccess 编译选项,强制开发者显示校验属性是否存在

    paths 可以不依赖 baseUrl 单独配置

    支持配置 "jsx": "react-jsx|react-jsxdev" 来指定是否使用 React17 的 jsx 和 jsxs 工厂函数

    编译器对 JSDoc @see 标签的支持

    不兼容变化abstract 成员不能再被标记为 async

    any/unknown 类型在 falsy 表达式中的类型推断方式改变

    declare let foo: unknown;

    declare let somethingElse: { someProp: string };

    let x = foo && somethingElse;

    /*ts3 x 类型为 { someProp: string }ts4 x 类型为 unknown*/Promise.resolve 函数参数不再是可选的

    spread 运算符的扩展数据类型其对应属性变为可选

    interface Person {

    name: string;

    age: number;

    location: string;

    }

    interface Animal {

    name: string;

    owner: Person;

    }

    function copyOwner(pet?: Animal) {

    return {

    ...(pet && pet.owner),

    otherStuff: 123

    }

    }

    /*ts3 返回类型为 { x: number } | { x: number, name: string, age: number, location: string }ts4 返回类型为 { x: number; name?: string; age?: number; location?: string;}*/

    参考文章Announcing TypeScript 4.1 | TypeScript​devblogs.microsoft.com

    展开全文
  • 转自:https://juejin.cn/post/68982703130505379971.索引类型 keyof 索引类型查询操作,可以获取泛型T上所有的 public 属性名构成联合类型classPerson{name:string="胡先生"age:number=18privateUserId:number=...

    转自:https://juejin.cn/post/6898270313050537997

    1.索引类型

    keyof 索引类型查询操作符,可以获取泛型T上所有的 public 属性名构成联合类型

    class Person {
        name: string = "胡先生"
        age: number = 18
        private UserId: number = 123
    }

    type PropNames = keyof Person
    da5181baee6fade5d76c2f6dc1bfd284.png

    注意:

    1. keyof只能获取泛型上的 public 属性名,属性名为字符串类型,
    2. keyof返回的是联合类型

    [] 索引类型访问操作符,类似js访问对象的某个属性值的语法,在TS中,它可以用来访问某个属性的类型

    class Person {
        name: string = "胡先生"
        age: number = 18
        time: Date = new Date()
        private UserId: number = 123
    }

    type PropNames = keyof Person // "name"|"age"|"time"

    type NameType = Person["name"]

    type PropTypes = Person[PropNames]
    e540a3ce6322a90041cb342f6745c990.png

    T["属性名"] 可以单独获取某个属性名的类型

    5c2c93fd0ecab9decc21a5ced6285a83.png

    T[keyof T] 可以拿到泛型T中所有 public属性的类型 的联合类型

    有了上面的基础后,我们可以实现下 pick 函数,pick函数可以从对象上取出指定的属性

    function pick(obj: T, prop: K): T[K] {return obj[prop]
    }

    K extends keyof T 指K可以赋值 给泛型T所有public属性 的联合类型,T[K]返回的就是泛型T上的 属性类型

    const User = {
        name: "胡先生",
        age: 18,
        id: 12345
    }
    const nameValue = pick(User, "name")//胡先生
    385ef51e8fe524618395fe07a08638a1.png

    如图keyof T = "name"|"age"|"id"
    所以K = "name"|"age"|"id" ,即prop的可选属性是"name"|"age"|"id"

    2.映射类型

    映射类型的语法是:[K in Keys] ,类似JS的数组方法forEach,遍历keys,并将值赋值给K
    上面我们已经实现了一个pick函数,现在我们想实现一个TS工具类型MyPick,从泛型T中挑选出需要的属性

    //定义一个泛型T,并且要从T中选出需要的属性,则要定义K 的类型是T所有public **属性名** 的联合类型
    type MyPick={// K是一个联合类型,我们需要遍历K,使用映射类型的语法[K in Keys]
      [P in K]:T[P]// P是属性名,T[p]则可以拿到属性类型
    }
    type MyPick={
        [P in K]:T[P]
    }interface User{
        name:string,
        age:number,
        id:number
    }
    type name = MyPick"name">
    753a0485b9ed400d7951f5b4d68eef1a.png

    TS工具类型中有个 Partial ,可以将所有类型变成可选的

    // 定义一个泛型T
    type MyPartial={// keyof T 可以拿到泛型T中所有pubilc的属性名// in 可以遍历所有属性名,并将属性名赋值给K// 则T[K]就是属性类型//?代表可选
      [K in keyof T]?:T[K]
    }
    type User = {
        id: number,
        name: string
    }

    type PartialUser = MyPartial
    5e034d8daa0a0e38cd18ed47af2a59b4.png

    3.条件类型

    T extends U ? X : Y 如果T 能赋值给U,则返回类型X 否则返回类型Y

    type IsStringOrNumber = T extends string ? string : number// 字符串"123"传递给了T,即"123"如果能赋值给string,则返回string,否正返回number
    type str = IsStringOrNumber<"123">
    81949a8643f0da7aa047ec24f703d035.png

    注意 :是 T能不能赋值给U,而不是T是不是U类型,因为U可能是any,是所有类型的子类型,例如 type IsStringOrNumber = T extends any ? string : number 只要T是能赋值给any的任何类型,该表达式就只返回string类型

    3.1条件类型和联合类型

    条件类型和联合类型结合,可以形成 分布式有条件类型,举个例子

    // 在T中找到不存在U中的类型,并返回
    type Diff = T extends U ? never : T
    type DiffType = Diffboolean, undefined | string>
    389d8cf0b23592383a3fe41296039d40.png

    上面的代码相当于

    type DiffType2 = Diff 
      | Diff
                    | Diff<boolean, undefined | string>
    860f7cec8770406ff6359398f5adbe26.png

    当T类型是联合类型number | string | boolean ,会分别将number | string | boolean

    赋值给Diff
    注意 :

    1. 只有裸类型参数才能实现分布式有条件类型,
    2. 裸类型参数,即类型参数不能被包裹在其他类型中,如数组,元组,函数,Promise等
    // 泛型T被包裹在[T],所以不在是裸类型参数了
    type Diff = [T] extends [U] ? never : T
    type DiffType = Diffboolean, undefined | string>
    41fea09c2f89095d9e8e850bc9e6e5e4.png

    当T被数组包裹[T]时,就不能实现分布式有条件类型了,上面代码等同于

    type DiffType = [number | string | boolean] extends [undefined | string] 
     ? never
         : number | string | boolean
    b24465cd24f155b37a503be9c25ba846.png

    3.2 条件类型与映射类型

    现在我们实现一个类型工具,取出必选类型

    interface User {
        id?: number
        name: string
        age: number
    }


    type NullableKeys = {// 如果k是id,T[k]=number|undefined// 所以只要undefined extends T[k] 就可以知道K是可选属性
        [K in keyof T]-?: undefined extends T[K] ? never : K
    }[keyof T]
    type keys = NullableKeys// [keyof T] = ["id"|"name"|"age"]
    2d4287898db7f4df5b422e1216306a01.png

    注意 :

    1. + - 用于映射类型中,给属性添加修饰符,-?即是减去可选的,将可续属性变成必选,-readonly将可读属性变成非只读
    2. 如果不写 -? ,虽然通过 undefined extends T[k] 找到了属性id,并且属性id的值被赋值为never,但是因为没有去除 ? ,TS会默认给 id 添加上 undefined 的值
    type NullableKeys = {//不加-?
        [K in keyof T]: undefined extends T[K] ? never : K
    }//注意这里没有keyof了
    type keys = NullableKeys
    f03a90cbb8c885626a7e6ad3cefe01db.png

    如图,不添加-?,id被赋值为undefined

    type NullableKeys = {//加-?
        [K in keyof T]-?: undefined extends T[K] ? never : K
    }//注意这里没有keyof了
    type keys = NullableKeys
    b0f56bef96d48929b35da6565c100d91.png

    4. infer

    infer可以在条件语句中充当类待推断的类型变量
    假如我们想知道一个数组中的元素类型,我们可能会这么做

    type ElementOf = T extends Array ? string : T extends Array ? number : ...

    按上面的写法,需要写出每个类型的条件语句,太过繁琐 我们可以看到数组的元素类型是一个变量,我们可以使用infer去声明这个变量

    type ElementOf = T extends Array ? E :never
    type strArr= Array
    type arrType = ElementOf
    bf3cb5c758509c618abc4f5ee56d6b38.png

    5. 阅读utility-types的源码

    github.com/piotrwitek/…

    1.IfEquals

    可以判断两个类型是否相同,并自定义返回的类型

    type IfEquals = (() => T extends X ? 1 : 2)
     extends () => T extends Y ? 1 : 2
       ? A
       : B;

    如果泛型X 和 泛型 Y相同,则返回 A,否正返回B

    1. (()=> T extends X ? 1 : 2)这是一个表达式,不会执行
    2. (()=> T extends Y ? 1 : 2) ,同上这是一个表达式
    3. 如果两条表达式相同,则返回A,否则返回B

    2.MutableKeys

    拿到一个对象的所有属性名( 除了readonly)的联合类型

    /*
     * @example
     *   type Props = { readonly foo: string; bar: number };
     *
     *   // Expect: "bar"
     *   type Keys = MutableKeys;
     */

    export type MutableKeys = {
      [P in keyof T]-?: IfEquals<
        { [Q in P]: T[P] },
        { -readonly [Q in P]: T[P] },// -readonly 是将只读属性变成非只读属性
        P
      >;
    }[keyof T];
    1. 上面有疑问的地方是为啥需要[Q in P]:T[P],Q其实没有使用到,但如果没有写[Q in P],我们只能拿到P这个字符串,而不能拿到readonly这个属性
    2. 详情可以看这篇知乎www.zhihu.com/question/36…

    3. ReadonlyKeys

    拿到一个对象所有readonly的属性名的联合类型

    /*
     * @example
     *   type Props = { readonly foo: string; bar: number };
     *
     *   // Expect: "foo"
     *   type Keys = ReadonlyKeys;
     */

    export type ReadonlyKeys = {
      [P in keyof T]-?: IfEquals<
        { [Q in P]: T[P] },
        { -readonly [Q in P]: T[P] },
        never,
        P
      >;
    }[keyof T];

    4.NonUndefined

    去除掉undefined

    /** 
     * @example
     *   // Expect: "string | null"
     *   SymmetricDifference;
     */

    export type NonUndefined = A extends undefined ? never : A;

    5. FunctionKeys

    拿到对象中的所有函数名(包括可选与必选)的联合类型

    /** 
     * @example
     *  type MixedProps = {name: string; setName: (name: string) => void; someKeys?: string; someFn?: (...args: any) => any;};
     *
     *   // Expect: "setName | someFn"
     *   type Keys = FunctionKeys;
     */

    export type FunctionKeys = {
      [K in keyof T]-?: NonUndefined extends Function ? K : never;
    }[keyof T];
    1. T extends object 要求泛型T 必须能赋值给object,这样才能遍历T的属性名
    2. [K in keyof T] 遍历T的所有public属性名,并将属性名赋值给K
    3. -? T的每个字段都是必选,使得TS不会自动给字段赋值undefined
    4. 如果某个函数是一个可选属性,则 T[K] = ()=>{}|undefined ,那T[K] extends Function便不成立,所以需要用 NonUndefined 去除undefined的值

    6.Pick

    从泛型T中选出需要的属性

    type Pick = {
        [P in K]: T[P];
    };interface Person{
      name:string,
      id:number,
      age:number
    }
    type NewPerson = Pick"name"|"age">//{name:string,age:number}

    7. RequiredKeys

    拿到对象中所有必选的属性名的联合类型

    /**
     * @example
     *   type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };
     *
     *   // Expect: "req" | "reqUndef"
     *   type Keys = RequiredKeys;
     */

    export type RequiredKeys = {
      [K in keyof T]-?: {} extends Pick ? never : K;
    }[keyof T];
    1. {} extends {id:number} ? true : false 会返回 false ,因为id是必选属性,而 {} 对象中没有
    2. {} extends {id?:number} ? true : false 会返回 true ,因为id是可选属性,空对象也能赋值
    3. {} extends Pick ? never : K ,如果T[K]是可选属性则返回never,否则返回K
    4. -? 是让可选属性变成必选,不然 ,K?:neverK前面有个 ? TS会将其变成 K?:never|undefined ,这样子[keyof T]取出的值就含有undefined ,所以要加上 -?

    8.PickByValue

    从泛型T中的所有属性中找到属性类型能赋值给ValueType的属性

    /**
     * @example
     *   type Props = { req: number; reqUndef: number | undefined; opt?: string; };
     *
     *   // Expect: { req: number }
     *   type Props = PickByValue;
     *   // Expect: { req: number; reqUndef: number | undefined; }
     *   type Props = PickByValue;
     */

    export type PickByValue = Pick<
      T,
      { [Key in keyof T]-?: T[Key] extends ValueType ? Key : never }[keyof T]
    >;
    1. Pick的第二个参数是一个联合类型,所以需要 [keyof T] 拿到泛型T的所有属性类型
    2. T[Key] extends ValueType ? Key : never 泛型T的属性类型能赋值给ValueType则返回Key,否则返回never
    3. 由1可知拿到属性类型,2可知[key in keyof T]:Key 可知{ [Key in keyof T]-?: T[Key] extends ValueType ? Key : never }[keyof T] 可以拿到T的所有属性名

    9. SetDifference

    A 如果能赋值给B,则返回never,否则返回A

    /*
     * SetDifference (same as Exclude)
     * @desc Set difference of given union types `A` and `B`
     * @example
     *   // Expect: "1"
     *   SetDifference;
     *
     *   // Expect: string | number
     *   SetDifference void), Function>;
     */

    export type SetDifference = A extends B ? never : A;

    10.Omit

    找到泛型T中除了K以外的其他属性

    /*
     * @example
     *   type Props = { name: string; age: number; visible: boolean };
     *
     *   // Expect: { name: string; visible: boolean; }
     *   type Props = Omit;
     */

    export type Omit = Pick>;
    1. keyof T 返回T的属性名的联合类型
    2. SetDifference 从T中找到不存在K中的属性名的联合类型C
    3. Pick 从T中找到属性名在C中的属性

    11.Intersection

    拿到两个泛型中共同的属性

    /* @example
     *   type Props = { name: string; age: number; visible: boolean };
     *   type DefaultProps = { age: number };
     *
     *   // Expect: { age: number; }
     *   type DuplicateProps = Intersection;
     */

    export type Intersection = Pick<
      T,
      Extract & Extract
    >;
    1. type Extract = T extends U ? T : never;
    2. Extract & Extract 可以拿到T和U的属性的交集

    12. Diff

    找到T中不存在于U上的属性

    /* @example
     *   type Props = { name: string; age: number; visible: boolean };
     *   type DefaultProps = { age: number };
     *
     *   // Expect: { name: string; visible: boolean; }
     *   type DiffProps = Diff;
     */

    export type Diff = Pick<
      T,
      SetDifference
    >;
    1. SetDifference 从T中找到不存在U中的属性的联合类型

    13.DeepPartial

    将所有属性递归变成可选属性

    export type DeepPartial = T extends Function
      ? T
      : T extends Array
      ? _DeepPartialArray
      : T extends object
      ? _DeepPartialObject
      : T | undefined;/** @private */// tslint:disable-next-line:class-name
    export interface _DeepPartialArray<Textends Array<DeepPartial<T>> {}/** @private */
    export type _DeepPartialObject = { [P in keyof T]?: DeepPartial };
    1. T extends Function 判断T是不是可以赋值给Function,是的话返回T,
    2. T extends Array 判断T是不是可以赋值给Array,因为不知道是什么类型的Array,所以用 infer U 作为一个类型变量代指,当T可以赋值给Array时,我们需要递归Array中的每一项,Array>
    3. T extends Object 判断T是不是可以赋值给Object,是的话,我们需要递归遍历Object中的每个属性, [P in keyof T] 遍历T的属性名, DeepPartial 将T 的属性类型传进 DeepPartial 进行递归

    结语

    如果有错漏的地方,还请看官们指正

    展开全文
  • 抽象方法必须被子类实现(抽象方法必须使用 abstract 关键字声明,且可以包含访问修饰符) abstract class Person { public love: string; constructor(love: string) { this.love = love; } abstract sayLove(): ...
  • TS-修饰符 与 static

    2019-07-19 14:42:59
    TS-修饰符 与 static 1.static: 用于 修饰 变量 或者方法,表示 静态的 当类 中 的 方法 被 声明 为 static 时,其实例化 对象 不可 调用 该方法,只有 类 本身 ,以及 其子类 可以 调用。 eg: class A { name:...
  • TypeScript中的访问修饰符 ​ 访问修饰符指的就是可以在类的成员前通过添加关键字来设置当前成员的访问权限。typescript中主要有三个访问修饰符: ​ 1、public: 公开的,默认 任何对象在任何地方都可以进行访问 ​ ...
  • 修饰符的分类 1.public:公有, 在类 子类 和类外面 都可以被访问到 2.protected :保护 ,在类 , 子类里面可以访问到,在类外面访问不到 3.private:私有 ,只能在类里面访问,子类 类外部都不可以访问 ...
  • number constructor(name:string, age:number, stuNo: number){ super(name, age) this.stuNo = stuNo } getStuNo() { return this.stuNo } } let s1 = new Student('111', 11, 1) 修饰符: // 修饰符 public ...
  • TS中类与类的继承、修饰符

    千次阅读 2019-07-10 17:37:18
    1、ts定义类 class class Person { public name: string //属性 public关键词可省略 constructor(name: string) { //构造函数 实例化触发的方法 this.name = name; } getName(): string { return this.name; } set...
  • ts中类的定义、继承、修饰符

    千次阅读 2019-06-08 17:04:45
    ts中类的定义 class Person{ name: string // 属性 前面省略了public关键词 age: number // 构造函数,实例化类的时候触发的方法 constructor(name:string, age:number){ this.name = name this....
  • 自己搞一个ts文件 里面写代码如下,试一下就行了 /* 1、vscode配置自动编译 1.第一步 tsc --inti 生成tsconfig.json 改 "outDir": "./js", 2、第二步 任务 - 运行任务 监视tsconfig.json 2、...
  • ${this.age}` } } let foo = new Foo('小明',12) // Foo {name:'小名',age:12,__proto__:getName(){}} ts定义类: class Foo { public name:string // 需要提前声明值,默认为public public age:number public ...
  • //err //修饰符 //public 修饰的属性或方法是共有的,可以在任何地方被访问到,默认所有属性和方法都是public的 //private 修饰的属性或方法是私有的,不能在声明它的类的外部访问 //protected 修饰的属性或方法是...
  • TypeScript中访问修饰符

    2020-01-03 11:01:36
    ts支持以下访问修饰符: public:所有定义成public的属性和方法都可以在任何地方进行访问。 class Animal { public age:number=10; public run() { console.log("这是一个跑的方法") } } class Dog extends ...
  • 3.访问修饰符(用的比较多) //public(公有的,默认是公有的)/private(私有的)/protected(受保护的,可以共享,分享给子类) 4.静态属性和静态方法 一。在js中 二。在TS中 5.抽象类和多态 多态 多种...
  • 文章目录类的定义例1例2类的继承类里面的修饰符多态抽象类 类的定义 例1 class Person{ name:string; //属性 省略public constructor(n:string){ //构造函数,实例化类的时候出发的方法 this.name = n } run():...
  • 一,前言 基于原型prototype的JS,一直在模拟面向对象, ...在TS中,对ES6的类进行了增强,引入了更多特性 二,定义一个类 使用TS定义一个类: class Dog { constructor(name: string) { this.name = name; } na...

空空如也

空空如也

1 2 3 4 5 6
收藏数 111
精华内容 44
关键字:

ts修饰符