EdwardZZZ / articles

工作点滴记录
2 stars 0 forks source link

TS type #68

Open EdwardZZZ opened 4 years ago

EdwardZZZ commented 4 years ago
// function  test2(...args: [string, number, boolean]) {
//     return true
// }
// // test2(1, 2, 3) // 报错
// test2('a', 2, true);

// type Head<T extends any[]> = T[0] // lookup type

// type t = typeof test2;
// type p = Parameters<t>;
// type head = Head<p> // 结果为string

// // type Tail<T> = T extends (head: any, ...tail: infer U) ? U : never;
// type Tail<A extends any[]> = ((...args: A) => any) extends ((h: any, ...t: infer T) => any) ? T : never

// type Length<T extends any[]> = T['length']
// // type Last<T> = T[Length<T> -1]

// type Last<T extends any[]> = T[Length<Tail<T>>];

// const t1 = [1, '2', '3'] as const;

// const t2 = typeof t1;

// type TypeName<T> =
//     T extends string ? "string" :
//     T extends number ? "number" :
//     T extends boolean ? "boolean" :
//     T extends undefined ? "undefined" :
//     T extends Function ? "function" :
//     "object";

// type T12 = TypeName<string | string[] | undefined>;  // "string" | "object" | "undefined"
// type T11 = TypeName<string[] | number[]>;  // "object"

// type ContainName<T> = T extends { name: string } ? T : never;

// type ContainAge<T> = T extends { age: number } ? T : never;

// type Boxed<T> = T extends any ? { value: T } : never;
// type Boxed2<T> = any extends T ? { value: T } : never;
// type Boxed3<T> = [T] extends any ? { value: T } : never;

// type a = Boxed<'a' | 'b'>  // distributed {value: 'a'} | {value: 'b'} 
// type b = Boxed2<'a' | 'b'>  // non distributive { value: 'a' | 'b'}
// type c = Boxed3<'a' | 'b'> // { value: 'a' | 'b'}

// type Check<T> = T extends true ? 'true' : 'false'

// type d = Check<any> // 'true' | 'false'
// type e = Check<boolean> // 'true' | 'false'
// type e1 = Check<true>;

// type res = Boxed<never> // 结果为never
// type res2 = never extends any ? { value: never} : never; // 结果为 { value: never}

// type Diff<T, U> = T extends U ? never : T;  // Remove types from T that are assignable to U
// type T30 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // "b" | "d"

// type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
// type T10 = Foo<{ a: string, b: string }>;  // string
// type T13 = Foo<{ a: string, b: number }>;  // string | number

// type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
// type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>;  // string
// type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>;  // string & number

type ReturnType2<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : 'bomb';

type a = ReturnType2<never>
type b = ReturnType2<any>
// type c = ReturnType2<unknown>
type d = any extends () => void ? true : false;

// function add(x:string,y:string):string;
// function add(x:number, y:number):number;
// function add(x:string|number, y: number|string): number | string{
//   if(typeof x === 'string'){
//     return x + ',' + y;
//   }else {
//     return x.toFixed() + (y as number).toFixed();
//   }
// }
// let x = add('1','2') // string
// let y = add(2,3) // number

// function add(x:string,y:string):string;
// function add(x:number, y:number):number;
// function add(x:string|number|Function, y: number|string): number | string
// function add(x:string|number|Function, y: number|string): number | string{
//   if(typeof x === 'string'){
//     return x + ',' + y;
//   }else {
//    return 1;
//   }
// }
// let x = add(1,2)
// let z = add(() => {},1)

// function add(x:string, y:string):string;
// function add(x:number, y:number):number; // 报错,implementation没有实现该overload signatue

// function add(x:string, y: number|string): number | string{
//   if(typeof x === 'string'){
//     return x + ',' + y;
//   }else {
//    return 1;
//   }
// }
// let x = add(1,2)

// function len(s: string): number;
// function len(arr: any[]): number;
// function len(x: any) {
//   return x.length;
// }
// len(""); // OK
// len([0]); // OK
// let t = Math.random() > 0.5 ? "hello" : [0]
// len(t);

// // 因此这里就不要用重载了,直接用union type吧
// function len(x: any[] | string) {
//     return x.length;
// }
// let t = Math.random() > 0.5 ? "hello" : [0]
// len(t); // 没问题了

// function padLeft(padding: number | string, input: string) {
//     return new Array(padding + 1).join(" ") + input; // 报错,string + 1 不合法
// }
function padLeft(padding: number | string, input: string) {
    if (typeof padding === "number") {
        return new Array(padding + 1).join(" ") + input;
    }
    return padding + input; // 此时padding的类型被narrowing为string了 
}

// interface Fish {
//     swim(): void;
// }
// interface Bird {
//     fly(): void;
// }
// function move(pet: Fish | Bird) {
//     if ("swim" in pet) {
//         return pet.swim();
//     }
//     return pet.fly();
// }

// function printAll(strs: string | string[] | null) {
//     if (typeof strs === "object") {
//         for (const s of strs) {
//             console.log(s)
//         }
//     }
//     else if (typeof strs === "string") {
//         console.log(strs)
//     }
//     else {
//         // do nothing
//     }
// }

// interface Foo {
//     foo: number;
//     common: string;
// }

// interface Bar {
//     bar: number;
//     common: string;
// }

// function isFoo(arg: any): arg is Foo {
//     return arg.foo !== undefined;
// }
// function doStuff(arg: Foo | Bar) {
//     if (isFoo(arg)) {
//         console.log(arg.foo); // OK
//         console.log(arg.bar); // Error!
//     }
//     else {
//         console.log(arg.foo); // Error!
//         console.log(arg.bar); // OK
//     }
// }

// interface Circle {
//     kind: "circle";
//     radius: number;
// }

// interface Square {
//     kind: "square";
//     sideLength: number;
// }

// type Shape = Circle | Square;

// //cut
// function getArea(shape: Shape) {
//     switch (shape.kind) {
//         case "circle":
//             return Math.PI * shape.radius ** 2;
//         case "square":
//             return shape.sideLength ** 2;
//     }
// }

interface Circle {
    kind: "circle";
    radius: number;
}

interface Square {
    kind: "square";
    sideLength: number;
}
interface Rectangle {
    kind: 'rectangle',
    width: number;
    height: number;
}
type Shape = Circle | Square | Rectangle;

//cut
// 在开了noimplicitReturn:true情况下,会提示我们Not all code paths return a value.ts(7030)
// function getArea(shape: Shape) { 
//     switch (shape.kind) {
//         case "circle":
//             return Math.PI * shape.radius ** 2;
//         case "square":
//             return shape.sideLength ** 2;
//     }
// }

// function assertNever(x: never): never {
//     throw new Error("Unexpected object: " + x);
// }
// //cut
// function getArea(shape: Shape) {
//     switch (shape.kind) {
//         case "circle":
//             return Math.PI * shape.radius ** 2;
//         case "square":
//             return shape.sideLength ** 2;
//         /*
//         case 'rectangle':
//             return shape.height * shape.width;
//         */
//         default:
//             return assertNever(shape); // 这里会type error,提示我们rectangle无法赋值给never
//     }
// }
EdwardZZZ commented 4 years ago
declare module 'koa' {
    interface Context {
        session: {
            set(key: string, value: any): void;
            get(key: string): string;
            remove(key: string): void;
        };
    }
}

declare module 'koa' {
    interface Context {
        setLocale(locale: string): void
    }
}
EdwardZZZ commented 3 years ago

class Test {
    protocol: string;

    create(protocol: string) {
        this.protocol = protocol;

        return this;
    }

    test() {
        console.log(this.protocol);
    }
}

function ProxyFactory<T>(clazz: new () => T, protocol: string): T {
    return Reflect.construct(clazz, []).create(protocol);
}

ProxyFactory(Test, 'Hello');

const test = new Test();
EdwardZZZ commented 3 years ago
type MergeParameters<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

type B = {
    b: number;
};

type C = {
    c: string;
}

type BC = MergeParameters<B | C>

const obj: BC = {
    b: 2,
    c: 'c',
};
type RouterParameterTypes = string | number | boolean;

// if the type of a property is one of RouterParameterTypes, then convert the type of the property to be the key
type ValidPropertiesToKeys<T> = { [P in keyof T]: T[P] extends RouterParameterTypes ? P : never; };

// get all property types that is not never
type ValidPropertyTypes<T> = T[keyof T];

// remove properties that do not have a type in RouterParameterTypes
type FilterOutInvalidProperties<T> = Pick<T, ValidPropertyTypes<ValidPropertiesToKeys<T>>>;

// A|B|... -> ((k:FIOP<A>)=>void)|((k:FIOP<B>)=>void)|... -> (k:FIOP<A>&FIOP<B>&...)=>void -> FIOP<A>&FIOP<B>&...
type MergeParameters<U> = (U extends any ? (k: FilterOutInvalidProperties<U>) => void : never) extends ((k: infer I) => void) ? I : never;

export interface RouterPattern<T> {
    match(url: string): T | undefined;
}

export function route<T>(strings: TemplateStringsArray): RouterPattern<{}>;
export function route<T>(strings: TemplateStringsArray, ...values: T[]): RouterPattern<MergeParameters<T>>;
export function route(strings: TemplateStringsArray, ...values: {}[]): {} {
    return {
        match(url: string): undefined {
            return undefined;
        }
    };
}
EdwardZZZ commented 3 years ago

class Base {}

export abstract class IModelService extends Base {
    abstract getName(id: number): string;
}

export class ModelService extends IModelService {
    getName(id: number): string {
        throw new Error("Method not implemented.");
    }
}

const service = new ModelService();
console.log(service instanceof Base); // ==> true;

function isExtends(a: object, b: object) {
    if (!a) return false;
    if (a === b) return true;

    return isExtends(Reflect.getPrototypeOf(a), b);
}
console.log(isExtends(ModelService, Base)); // ==> true;
EdwardZZZ commented 3 years ago
export type UnionToTuple<T> = (
    (
        (
            T extends any
            ? (t: T) => T
            : never
        ) extends infer U
        ? (U extends any
            ? (u: U) => any
            : never
        ) extends (v: infer V) => any
        ? V
        : never
        : never
    ) extends (_: any) => infer W
    ? [...UnionToTuple<Exclude<T, W>>, W]
    : []
);

type A = {
    a: number
}

type B = {
    b: string
}

type U<T> = T extends any ? (t: T) => T : never

type C = U<A|B>;

type TC<U> = (U extends any
    ? (u: U) => any
    : never
) extends (v: infer V) => any
? V
: never;

type D = TC<A|B>;
type E = TC<U<A|B>>;

type W<T> = TC<U<T>> extends (_: any) => infer W ? W : never;

type F = W<A|B>;

type TT<T> = W<Exclude<A|B, W<A|B>>>

type G = TT<A|B>;