Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

TypeScript Quiz (Encraft #12 Frontend Quiz Night)

uhyo
March 28, 2024

TypeScript Quiz (Encraft #12 Frontend Quiz Night)

2024-03-28 Encraft #12 Frontend Quiz Night

uhyo

March 28, 2024
Tweet

More Decks by uhyo

Other Decks in Technology

Transcript

  1. 第1問 解説 返り値に表れるリテラル型が1つか2つ以上かによって 挙動が異なる。 // string function getHello() { return "hello";

    } // “hello” | “world” function getHelloOrWorld() { if (Math.random() < 0.5) { return "hello"; } else { return "world"; } }
  2. 第1問 解説 実装当初から一貫してこの挙動で、理由はPR内で 説明されている。 The issue is that you practically never

    want the literal type. After all, why write a function that promises to always return the same value? https://github.com/microsoft/TypeScript/pull/10676#issuecomment-244257359 (要約)常に特定の値を返す関数なんて書かんでしょ
  3. 第2問 このコードで、KeysとValuesはど んな型? (選択肢は Keys / Values の形) const values

    = { foo: 123, bar: 456, } satisfies Record<string, number>; type Keys = keyof typeof values; type Values = typeof values[Keys]; 1: string / number 2: “foo” | “bar” / number 3: string / 123 | 456 4: “foo” | “bar” / 123 | 456
  4. 第2問 このコードで、KeysとValuesはど んな型? (選択肢は Keys / Values の形) const values

    = { foo: 123, bar: 456, } satisfies Record<string, number>; type Keys = keyof typeof values; type Values = typeof values[Keys]; 1: string / number 2: “foo” | “bar” / number 3: string / 123 | 456 4: “foo” | “bar” / 123 | 456 正解は……
  5. 第2問 このコードで、KeysとValuesはど んな型? (選択肢は Keys / Values の形) const values

    = { foo: 123, bar: 456, } satisfies Record<string, number>; type Keys = keyof typeof values; type Values = typeof values[Keys]; 2: “foo” | “bar” / number
  6. 第2問 解説 なので実はsatisfiesが 無くても結果が同じ。 const values = { foo: 123, bar:

    456, }; type Keys = keyof typeof values; type Values = typeof values[Keys]; valuesの型は { “foo”: number; “bar”: number; } なのでKeysは “foo” | “bar”、 Valuesは number となる。
  7. 第2問 解説 このケースでsatisfiesを使う目的は、 オブジェクトのプロパティに数値以外が入るのを防ぐこと。 const values = { foo: 123, bar:

    456, baz: “789”, // 型エラー } satisfies Record<string, number>; type Keys = keyof typeof values; type Values = typeof values[Keys];
  8. 第2問 解説 const values = { foo: 123, bar: 456, }

    as const satisfies Record<string, number>; type Keys = keyof typeof values; type Values = typeof values[Keys]; Valuesの型も具体的に欲しい場合は、 このようにas constと併用するとよい。 こうするとValuesは123 | 456 型になる。
  9. 第3問 type Data1 = string | number; function useData1(data: Data1)

    { if (typeof data === "number") { 0 <= data && data <= 10; } } 1
  10. 第3問 type Data2 = { type: "success"; value: number; }

    | { type: "error"; error: unknown; } function useData2(data: Data2) { if (data.type === "success") { 0 <= data.value && data.value <= 10; } } 2
  11. function useData3(data: object) { if ("foo" in data && typeof

    data.foo === "number") { 0 <= data.foo && data.foo <= 10; } } 3 第3問
  12. 第3問 function useData4( data: Record<string, unknown>, key: string, ) {

    if (typeof data[key] === "number") { 0 <= data[key] && data[key] <= 10; } } 4
  13. type Data1 = string | number; function useData1(data: Data1) {

    if (typeof data === "number") { 0 <= data && data <= 10; } } 1 type Data2 = { type: "success"; value: number; } | { type: "error"; error: unknown; } function useData2(data: Data2) { if (data.type === "success") { 0 <= data.value && data.value <= 10; } } 2 function useData3(data: object) { if ("foo" in data && typeof data.foo === "number") { 0 <= data.foo && data.foo <= 10; } } function useData4( data: Record<string, unknown>, key: string, ) { if (typeof data[key] === "number") { 0 <= data[key] && data[key] <= 10; } } 1 3 4 第3問 型エラーが発生するのはどれ?
  14. type Data1 = string | number; function useData1(data: Data1) {

    if (typeof data === "number") { 0 <= data && data <= 10; } } 1 type Data2 = { type: "success"; value: number; } | { type: "error"; error: unknown; } function useData2(data: Data2) { if (data.type === "success") { 0 <= data.value && data.value <= 10; } } 2 function useData3(data: object) { if ("foo" in data && typeof data.foo === "number") { 0 <= data.foo && data.foo <= 10; } } function useData4( data: Record<string, unknown>, key: string, ) { if (typeof data[key] === "number") { 0 <= data[key] && data[key] <= 10; } } 1 3 4 第3問 型エラーが発生 するのはどれ? 正解は……
  15. type Data1 = string | number; function useData1(data: Data1) {

    if (typeof data === "number") { 0 <= data && data <= 10; } } 1 type Data2 = { type: "success"; value: number; } | { type: "error"; error: unknown; } function useData2(data: Data2) { if (data.type === "success") { 0 <= data.value && data.value <= 10; } } 2 function useData3(data: object) { if ("foo" in data && typeof data.foo === "number") { 0 <= data.foo && data.foo <= 10; } } 1 3 第3問 解説 1~3は絞り込みが効くパターン。
  16. 第3問 解説 function useData4( data: Record<string, unknown>, key: string, ) {

    if (typeof data[key] === "number") { 0 <= data[key] && data[key] <= 10; } } 4 このように data[key] に対する絞り込みは、 keyがただのstring型の場合はできなかった。 次バージョンではCFAが拡張され、できるようになりそう。
  17. 第4問 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; このコードで、Output型は1~4のうちどれになる? 1: never 2: false 3: true 4: boolean
  18. 第4問 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; このコードで、Output型は1~4のうちどれになる? 1: never 2: false 3: true 4: boolean 正解は……
  19. 第4問 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; このコードで、Output型は1~4のうちどれになる? 4: boolean
  20. 第4問 解説 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; 条件型 (conditional types) の分配 (distribution) 知ってますか? という知識問題でした。 IsString<string | number> = (string extends string ? true : false) | (number extends string ? true : false) = true | false = boolean 型の計算の流れ①
  21. 第4問 解説 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; 条件型 (conditional types) の分配 (distribution) 知ってますか? という知識問題でした。 IsNotString<string | number> = Not<IsString<string | number>> = Not<boolean> = (true extends true ? false : true) | (false extends true ? false : true) = false | true = boolean 型の計算の流れ②
  22. 第5問 type Not<B extends boolean> = B extends true ?

    false : true; type IsString<T> = T extends string ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; // ^? Output = boolean 第4問のこのコードを、Output が true になるように修正します。 分配が起こらないように直せば修正できます。
  23. 第5問 type Not<B extends boolean> = B[] extends true[] ?

    false : true; type IsString<T> = T[] extends string[] ? true : false; type IsNotString<T> = Not<IsString<T>>; type Output = IsNotString<string | number>; // ^? Output = true 実は、このように直せば分配が起こらなくなり、修正できます。
  24. 第5問 type Not<B extends boolean> = B[] extends true[] ?

    false : true; type IsString<T> = T[] extends string[] ? true : false; type IsNotString<T> = Not<Not<Not<IsString<T>>>>; type Output = IsNotString<string | number>; // ^? Output = false しかし、調子に乗ってNotを3重にしたら壊れました。 Notの定義を変えることで、Outputがtrueとなる 正しい挙動に修正してください。
  25. 第5問 type Not<B extends boolean> = B[] extends true[] ?

    false : true; 修正前 type Not<B extends boolean> = readonly B[] extends readonly true[] ? false : true; 1 type Not<B extends boolean> = [B] extends [true] ? false : true; 2 type Not<B extends boolean> = {v:B} extends {v:true} ? false : true; 3 type Not<B extends boolean> = (()=>B) extends (()=>true) ? false : true; 4
  26. 第5問 type Not<B extends boolean> = B[] extends true[] ?

    false : true; 修正前 type Not<B extends boolean> = readonly B[] extends readonly true[] ? false : true; 1 type Not<B extends boolean> = [B] extends [true] ? false : true; 2 type Not<B extends boolean> = {v:B} extends {v:true} ? false : true; 3 type Not<B extends boolean> = (()=>B) extends (()=>true) ? false : true; 4 正解は……
  27. 第5問 type Not<B extends boolean> = B[] extends true[] ?

    false : true; 修正前 type Not<B extends boolean> = [B] extends [true] ? false : true; 2
  28. 第5問 解説 type Not<B extends boolean> = [B] extends [true] ?

    false : true; 2 修正前と1~4はどれも分配を避けられる書き方。 しかし、2のように[ ] で囲む(タプル型を使う)のが公式に推奨されるやり方で あり、ドキュメントにも書いてある。 https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types この問題の例のように、このやり方は型推論の面で少し優遇される。 参考: https://github.com/microsoft/TypeScript/issues/52068