Upgrade to Pro — share decks privately, control downloads, hide ads and more …

typescript_evolution_ngonair.pdf

 typescript_evolution_ngonair.pdf

ng on air 用の加筆版

Yosuke Kurami

April 02, 2019
Tweet

More Decks by Yosuke Kurami

Other Decks in Programming

Transcript

  1. ܕνΣοΫͱਪ࿦ w ؔ਺TVNͷ໭Γ஋͸OVNCFSͰ͋Δ͜ͱΛਪ࿦͢Δ function sum(a: number, b: number) { return

    a + b; } console.log(sum(1, sum(1, 1))); // OK // Argument of type '"a"' is not assignable to // parameter of type 'number' console.log(sum('a', 'b'));
  2. 4USVDUVBM4VCUZQJOH class Hoge { name = "Kurami"; } class Foo

    { name = "Quramy"; } function sayHello(obj: { name: string }) { console.log(obj.name); } sayHello(new Hoge()); sayHello(new Foo()); sayHello(new Error("error"));
  3. ༨ஊ /PNJOBMʹ͍ͨ͠ͱ͖ w ͨ·ʹߏ଄త෦෼ܕͩͱࠔΔ͜ͱ͕͋Δ w QSJWBUFϑΟʔϧυΛ࢖͏ϋοΫͰճආ͢Δ class DateISOString { private

    _ = Symbol("DateISOString"); readonly isoString = new Date().toISOString(); } function hoge(x: DateISOString) { console.log(x.isoString); } hoge(new DateISOString()); hoge({ isoString: "hoge" }); // Error
  4. 4USJDUDIFDL w TUSJDUΦϓγϣϯʢσϑΥϧτͰPOʣΛ෇͚͓ͯ͘ͱɺݎ ࿚ͳνΣοΫ͕Մೳʹ function hoge(x?: string) { //Object is

    possibly 'undefined'. return x.trim(); } function hoge(x?: string) { if (!x) return ""; return x.trim(); // OK }
  5. FT.PEVMFT*OUFSPQ w /PEFKTͰ͸ɺ$PNNPO+4͔ΒOBNFEJNQPSU͢ΔͱΤ ϥʔʹ /* hoge.mjs */ import { readFile

    } from "fs"; $ node --experimental-modules hoge.mjs SyntaxError: The requested module does not provide an export named ‘readFile' at checkComplete (internal/loader/ModuleJob.js:75:27) at moduleJob.linked.then (internal/loader/ModuleJob.js: 58:11) at <anonymous>
  6. XJUINPEJpFS w ͷ෇༩Ͱɺ࡞༻ͷ޲͖ ෇͚Δ֎͢ ΛදݱՄೳʹ type Optional<T> = { [P

    in keyof T]+?: T[P] }; type Strict<T> = { [P in keyof T]-?: T[P] }; type ReadOnly<T> = { +readonly [P in keyof T]: T[P] }; type Mutable<T> = { -readonly [P in keyof T]: T[P] };
  7. XJUINPEJpFS type Strict<T> = { [P in keyof T]-?: T[P]

    }; // Property 'name' is missing in type '{}' // but required in type 'Strict<{ name?: string | undefined; }>'. const x: Strict<{ name?: string }> = { };
  8. -FUTUZQF w ༡ΜͰΈΑ͏$POEJUJPOBM5ZQFT w %J⒎ w %J⒎͸ͲΜͳܕͰ͠ΐ͏͔ʁ type DiffKey<K1, K2>

    = K1 extends K2 ? never : K1; type $Diff<T, U> = { [P in DiffKey<keyof T, keyof U>]: T[P]; };
  9. %JTUSJCVUJPO w $POEJUJPOBM5ZQFTͱ6OJPO5ZQFTͷؒʹ͸෼഑཯͕੒ཱ w OFWFS͸͍͔ͳΔܕʹ΋୅ೖෆՄೳͳܕʢϘτϜܕʣ w type DiffKey<K1, K2> =

    K1 extends K2 ? never : K1; let key: DiffKey<("name" | "age"), "age">; // ("name" extends "age" ? never : "name") // | ("age" extends "age" ? never : "age") // = ("name" | never) // = "name"
  10. %J⒎ͷਖ਼ମ w 'MPXUZQFʹಉ໊ͷ6UJMJUZUZQF͕͋Γ·͢ type DiffKey<K1, K2> = K1 extends K2

    ? never : K1; type $Diff<T, U> = { [P in DiffKey<keyof T, keyof U>]: T[P]; }; const defaultProps = { age: 0 }; let requiredProps: $Diff<{ name: string; age: number; }, typeof defaultProps>; requiredProps = { name: "Quramy" };
  11. *OGFSBOE$BQUVSF w 5͕ؔ਺Ͱ͋Ε͹ɺͦͷ໭Γ஋ͱͯ͠ਪ࿦͞ΕΔܕ͕3ʹ֨ ೲ͞ΕΔ type Return<T> = T extends (...args:

    any[]) => infer R ? R : never; let r: Return<() => number>; // typeof r = number
  12. 3FEVYͬΆ͍ΞϨ type Return<T> = T extends (...args: any[]) => infer

    R ? R : never; type AppState<T> = { [P in keyof T]: Return<T[P]> }; const reducers = { name: (state: string, action: any) => state, age: (state: number, action: any) => state, }; let appState: AppState<typeof reducers>; // typeof appState = { name: sting, age: number }
  13. 3FTUQBSBNFUFSTXJUI UVQMFUZQFT w WYҎલ͸3FTU1BSBNFUFS͸"SSBZUZQFͷΈ͕ڐ༰ w WY͔Β͸5VQMFUZQF΋ར༻Մೳʹ function hoge(...args: any[]) {

    const a1 = args[0]; const a2 = args[1]; const a3 = args[2]; } function foo(...args: [string, number]) { const a0 = args[0]; // string const a1 = args[1]; // number const a2 = args[2]; // error }
  14. 4QSFBEFYQSFTTJPOTXJUI UVQMFUZQFT w 4QSFBE0QFSBUPSʹΑΔؔ਺ݺͼग़͠ʹରԠ
 Ҏલ͸DPNQJMFFSSPSʹͳͬͯ͠·͍ͬͯͨ  w WY͔Β͸5VQMFUZQF΋ར༻Մೳʹ declare function

    foo(a: number, b: number): void; const args1 = [1, 2] as [number, number]; foo(...args1); const args2 = [1, "bar" ] as [number, string]; // Argument of type 'string' is not assignable to // parameter of type 'number'. foo(...args2);
  15. (FOFSJDSFTUQBSBNFUFST w 3FTU1BSBNFUFSTʹ૯শܕ͕ར༻Մೳʹ w +BWB4DSJQUGVODUJPOͷCJOEDBMMBQQMZͱͷ਌࿨ੑ޲্
 ޙड़ͷTUSJDU#JOE$BMM"QQMZͷૅ declare function curry<T, U

    extends any[], R>( fn: (x: T, ...args: U) => R ): (x: T) => (...args: U) => R; const sum = (a: number, b: number) => a + b; const bound = curry(sum)(1); const x = bound(2); // type of x = number const error = bound("hoge"); // error
  16. 3FTUFMFNFOUTJOUVQMF UZQFT w 5VQMF5ZQFதʹ3FTUͳUZQFΛදݱͰ͖ΔΑ͏ʹͳͬͨ w ؔ਺ͷ3FTU1BSBNFUFSTͱͯ͠΋ར༻Մೳ function hoge<T extends any[]>(...args:

    T) { return args; } const arr = [1, 2, 3]; const v = hoge("hoge", ...arr); // typeof v = [string, ...number[]] type Hoge = [string, ...number[]];
  17. Y type Box<V> = { value: V }; type Boxing<T>=

    { [P in keyof T]: Box<T[P]>; }; type User = { name: string, age: number, }; const boxedUser: Boxing<User> = { name: { value: "quramy" }, age: { value: 18 }, }; let boxedNumbers: Boxing<number[]>; boxedNumbers.concat.value([]); // ??? boxedNumbers.length.value; // ???
  18. Y w LFZPGOVNCFS<>ͷҙຯ͕มΘͬͨΘ͚Ͱ͸ͳ͍఺ʹ஫ҙ type Box<V> = { value: V };

    type Boxing<T>= { [P in keyof T]: Box<T[P]>; }; const boxedNumbers: Boxing<number[]> = [ { value: 1 }, { value: 100 }, ];
  19. ࢖͍Έͪ w $POEJUJPOBMUZQF (FOFSJDSFTUQBSBNFUFST .BQQFE UVQMFUZQFͷ߹ΘٕͤͷྫΛ঺հ w ͓୊SYKTͷDPNCJOF-BUFTUؔ਺ʢ˞1SPNJTFBMMతͳౕʣ interface Observable<T>

    { subscribe(cb: (v: T) => void): void; } declare var s1$: Observable<string>; declare var s2$: Observable<number>; combineLatest(s1$, s2$).subscribe(([s1, s2]) => { console.log(s1); // typeof s1 = string console.log(s2); // typeof s2 = number });
  20. ࢖͍Έͪ interface Observable<T> { subscribe(cb: (v: T) => void): void;

    } // Inference in conditional type type StreamType<T> = T extends Observable<infer S> ? S : never; // Mapped tuple type type Unboxing<U extends Observable<any>[]> = { [P in keyof U]: StreamType<U[P]>; }; // Generic rest parameters declare function combineLatest<U extends Observable<any>[]> (...args: U): Observable<Unboxing<U>>;
  21. TUSJDU#JOE$BMM"QQMZ w CJOE declare function hoge(a: number, b: string): void

    const hoge1 = hoge.bind(null, 1); hoge1("hoge"); hoge1(); // error hoge1(1); // error hoge1("hoge", 2); // error
  22. TUSJDU#JOE$BMM"QQMZ w DBMM declare function hoge(a: number, b: string): void

    hoge.call(null, 1, "hoge"); hoge.call(null, 1); // error hoge.call(null, "hoge"); // error hoge.call(null, 1, "hoge", 2); // error
  23. TUSJDU#JOE$BMM"QQMZ w BQQMZ declare function hoge(a: number, b: string): void

    hoge.apply(null, [1, "hoge"]); hoge.apply(null, [1]); // error hoge.apply(null, ["hoge"]); // error hoge.apply(null, [1, "hoge", 2]); // error
  24. ͜͏͍͏͜ͱΒ͍͠ declare function pipe<A extends any[], B, C>( ab: (...args:

    A) => B, bc: (b: B) => C ): (...args: A) => C; declare function list<T>(a: T): T[]; declare function box<V>(x: V): { value: V }; const listBox = pipe(list, box); // <T>(a: T) => { value: T[] } const boxList = pipe(box, list); // <V>(x: V) => { value: V }[] const x1 = listBox(42); // { value: number[] } const x2 = boxList("hello"); // { value: string }[] w ैདྷ͸ɺMJTU#PY͸(a: any) => { value: any[] } ʹͳͬ ͯ͠·ͬͨ
  25. ࠓߋײ͋Δ΍ͭ import { ComponentType } from "react"; type HoC<P1, P2>

    = (c: ComponentType<P1>) => ComponentType<P2>; declare function compose<P1, P2, P3>( hoc1: HoC<P1, P2>, hoc2: HoC<P2, P3>, ): (c: ComponentType<P1>) => ComponentType<P3>;
  26. import { ComponentType } from "react"; type $Diff<T, U> =

    { [P in Exclude<keyof T, keyof U>]: T[P] }; // HoCs declare function connect<P extends {}>(c: ComponentType<P>): ComponentType<$Diff<P, { count: number }>>; declare function withRouter<P extends {}>(c: ComponentType<P>): ComponentType<$Diff<P, { location: Location }>>; type Props = { className: string, location: Location, count: number, }; declare function MyComponent(props: Props): JSX.Element; // render props component const enhancer = compose( connect, withRouter, ); const MyContainer = enhancer(MyComponent); const App = () => <MyContainer className="app" />; // Outer Props͕ਪ࿦͞ΕΔ
  27. %FNP /* before */ import { hoge } from "./lib";

    import { foo } from "./lib"; // no used import import { bar } from "./lib"; hoge(); foo(); /* after */ import { hoge, foo } from "./lib"; hoge(); foo();
  28. &SSPS$PEFpY w UTTFSWFS -BOHVBHF4FSWJDF ʹ͓͚ΔΤϥʔpYͷྲྀΕ  HFU4VQQPSUFE$PEF'JYFTίϚϯυͰ-BOH4FSWJDF͕ରԠՄೳͳ ΤϥʔίʔυͷҰཡΛऔಘ͓ͯ͘͠  HFU&SSPSίϚϯυͰϑΝΠϧͷΤϥʔΛ-BOH4FSWJDF΁໰͍߹Θ

    ͤΔ  $PEF'JYαϙʔτର৅ͷΤϥʔίʔυͷ৔߹ɺHFU$PEF'JYFTίϚ ϯυͰमਖ਼಺༰Λ-BOH4FSWJDFʹ໰͍߹ΘͤΔ  ड͚औͬͨมߋ಺༰ 5FYU$IBOHF ΛΤσΟλͷόοϑΝʹద༻͢Δ
  29. 3FOBNFJNQPSU EFDMBSBUJPO w WYͰಋೖ w *NQPSUGSPNͷର৅෦෼ΛSFOBNFͰ͖ΔΑ͏ʹͳͬͨ /* fuga.ts */ export

    function fuga() { return "hoge"; } /* main.ts */ import { fuga } from "./fuga"; console.log(hoge());