• TypeScript Conditional Types All In One


    TypeScript Conditional Types All In One

     // SomeType extends OtherType ? TrueType : FalseType;
    
    
    type SomeType = number;
    type OtherType = any;
    type TrueType = number;
    type FalseType = string;
    
    type Stuff =SomeType extends OtherType ? TrueType : FalseType;
    // type Stuff = number
    
    
    interface IdLabel {
      id: number /* some fields */;
    }
    interface NameLabel {
      name: string /* other fields */;
    }
    
    function createLabel(id: number): IdLabel;
    // function createLabel(id: number): IdLabel (+2 overloads)
    
    function createLabel(name: string): NameLabel;
    // function createLabel(name: string): NameLabel (+2 overloads)
    
    function createLabel(nameOrId: string | number): IdLabel | NameLabel;
    // function createLabel(nameOrId: string | number): IdLabel | NameLabel (+2 overloads)
    
    function createLabel(nameOrId: string | number): IdLabel | NameLabel {
      throw "unimplemented";
    }
    // function createLabel(id: number): IdLabel (+2 overloads)
    
    // better solution ✅
    
    type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel;
    
    function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
      throw "unimplemented";
    }
    
    

    Conditional Type Constraints

    条件类型约束

    
    interface MessageType {
      message: unknown;
    }
    // type MessageOf<T> = T extends MessageType ? T["message"] : never;
    
    // 等价于
    type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;
     
    interface Email {
      message: string;
    }
     
    interface Dog {
      bark(): void;
    }
     
    type EmailMessageContents = MessageOf<Email>;
    // type EmailMessageContents = string
     
    type DogMessageContents = MessageOf<Dog>;
    // type DogMessageContents = never
    
    
    type Flatten<T> = T extends any[] ? T[number] : T;
    
    //  array, extracts out the element type
    type Str = Flatten<string[]>;
    // type Str = string
    type num = Flatten<number[]>;
    // type num = number
    
    // not array, leaves the type alone.
    type Num = Flatten<number>;
    // type Num = number
    type str = Flatten<string>;
    // type str = string
    
    
    

    Inferring Within Conditional Types

    在条件类型中推断

    type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
    // type Flatten<Type> = Type extends (infer Item)[] ? Item : Type
    
    
    
    // 可以从函数类型中提取返回类型
    type GetReturnType<Type> = Type extends (...args: never[]) => infer Return ? Return : never;
    
    type Num = GetReturnType<() => number>;
    // type Num = number
    
    type Str = GetReturnType<(x: string) => string>;
    // type Str = string
    
    type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
    // type Bools = boolean[]
    
    type VoidType = GetReturnType<() => void>;
    // type VoidType = void
    
    
    declare function stringOrNum(x: string): number;
    declare function stringOrNum(x: number): string;
    // 从具有多个调用签名的类型(例如重载函数的类型)进行推断时,从最后一个签名进行推断(这大概是最宽容的包罗万象的情况)
    // 无法根据参数类型列表执行重载决议。
    declare function stringOrNum(x: string | number): string | number;
    
    // type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
    
    type T1 = ReturnType<typeof stringOrNum>;
    // type T1 = string | number
    
    

    Distributive Conditional Types

    可分配条件类型

    type ToArray<Type> = Type extends any ? Type[] : never;
    
    // union type / 联合类型
    type StrArrOrNumArr = ToArray<string | number>;
    // type StrArrOrNumArr = string[] | number[]
    
    
    type StrArrOrNumArr2 = ToArray<string> | ToArray<number>;
    
    

    Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends keyword with square brackets.

    通常,分配性是期望的行为。为了避免这种行为,您可以用方括号将 extends 关键字的每一侧括起来。

    type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
     
    // 'StrArrOrNumArr' is no longer a union.
    type StrArrOrNumArr = ToArrayNonDist<string | number>;
    // type StrArrOrNumArr = (string | number)[]
    
    

    leetcode TypeScript 面试题

    https://www.cnblogs.com/xgqfrms/p/13611172.html

    // import { expect } from "chai";
    
    interface Action<T> {
      payload?: T;
      type: string;
    }
    
    class EffectModule {
      count = 1;
      message = "hello!";
      delay(input: Promise<number>) {
        return input.then((i) => ({
          payload: `hello ${i}!`,
          type: "delay"
        }));
      }
      setMessage(action: Action<Date>) {
        return {
          payload: action.payload!.getMilliseconds(),
          type: "set-message"
        };
      }
    }
    
    // 修改 Connect 的类型,让 connected 的类型变成预期的类型
    // type Connect = (module: EffectModule) => any;
    
    // 1. 过滤出成员属性的函数 ✅
    type FilterFunction<Obj> = {
      // 仅仅过滤 Function
      [K in keyof Obj]: Obj[K] extends Function ? K : never;
    }[keyof Obj];
    
    type Connect = (
      module: EffectModule
    ) => {
      // 2. 使用 infer 动态获取 参数类型
      [K in FilterFunction<EffectModule>]: EffectModule[K] extends (
        input: Promise<infer T>
      ) => Promise<Action<infer U>>
        ? (input: T) => Action<U>
        : EffectModule[K] extends (action: Action<infer T>) => Action<infer U>
        ? (action: T) => Action<U>
        : never;
      //  input & action 形参必须写死 ???
    };
    
    /*
    type Connect = (module: EffectModule) => {
      delay: (input: number) => Action<string>;
      setMessage: (action: Date) => Action<number>;
    }
    */
    
    const connect: Connect = (module) => ({
      delay: (input: number) => ({
        type: "delay",
        payload: `hello 2`
      }),
      setMessage: (input: Date) => ({
        type: "set-message",
        payload: input.getMilliseconds()
      })
    });
    
    type Connected = {
      delay(input: number): Action<string>;
      setMessage(action: Date): Action<number>;
    };
    
    export const test = connect(new EffectModule());
    /*
    type Connect = (module: EffectModule) => {
      delay: (input: number) => Action<string>;
      setMessage: (action: Date) => Action<number>;
    }
    */
    
    export const connected: Connected = connect(new EffectModule());
    
    

    refs

    https://www.typescriptlang.org/docs/handbook/2/types-from-types.html

    https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

    https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html



    ©xgqfrms 2012-2020

    www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

    原创文章,版权所有©️xgqfrms, 禁止转载 ️,侵权必究⚠️!


  • 相关阅读:
    .netcore利用DI实现级联删除
    识别手写数字增强版100%
    嗨!请查收这道有趣的面试题
    理解TCP/IP协议栈之HTTP2.0
    基于Redis的分布式锁和Redlock算法
    从生日悖论谈哈希碰撞
    Redis面试热点工程架构篇之数据同步
    Redis面试热点之底层实现篇(续)
    saltstack安装+基本命令
    25个iptables常用示例
  • 原文地址:https://www.cnblogs.com/xgqfrms/p/16218095.html
Copyright © 2020-2023  润新知