Open6

TypeScript Challenge

まっきんとっしゅまっきんとっしゅ

https://github.com/type-challenges/type-challenges/blob/master/questions/4-easy-pick/README.md

問題

組み込みの型ユーティリティPick<T, K>を使用せず、TからKのプロパティを抽出する型を実装します。(KはUnion型でもOK)

  • keyof T
    型Tのkeyだけを取得する

例)

type Point = { x: number; y: number };
type P = keyof Point;
// これは x | yと同じ
  • U extends keyof T
    型UはTのkeyのどれかになる

  • U extends keyof Tの具体例(https://negalog.com/typescript-keyof-generics/)

  • [P in K]
    for(item in list)みたいなノリ。Union型のKから型を一つずつ取り出してPに入る

  • T[P]
    JSのオブジェクトと同じ感じ。

type Type = {
 x:number,
 y:string
}

Type[x]numberがとれる。

解答

type MyPick<T , K extends keyof T> = { [P in K]: T[P] }

  • 使い方
    type Type = { x:number , y:string ,z:null}
    MyPick<Type ,z> = {x:number,y:string}
まっきんとっしゅまっきんとっしゅ

問題

https://github.com/type-challenges/type-challenges/blob/master/questions/11-easy-tuple-to-object/README.ja.md

タプルを受け取り、その各値のkey/valueを持つオブジェクトの型に変換する型を実装します。

  • タプル型
    配列の型
let a : [ string ,number]
a=[true,1]//NG
a=["mmm" , 1]//OK

解答

type TupleToObject<T extends readonly any[]> = {[K in T[number]]:K}
まっきんとっしゅまっきんとっしゅ

https://github.com/type-challenges/type-challenges/blob/master/questions/43-easy-exclude/README.ja.md

問題

組み込みの型ユーティリティExclude <T、U>を使用せず、Uに割り当て可能な型をTから除外する型を実装します。

解答

type MyExclude<T, U> = T extends U ? never : T
  • T :string|number|string[]
  • U: string[]
    の場合は
type a = MyExclude<T,U>=string | number;

となる。

type MyExclude<T, U> = T extends U ? never : T

これの一番左のTと一番右のTは中身が違う。なんか不思議な感じがする。

Conditional TypesにはUnion typesの分配則がある。

(T1 | T2) extends U ? X : Y = (T1 extends U ? X : Y) | (T2 extends U ? X : Y)

なのでこれを使うと

type MyExclude<string|number|string[],string[]>
=  string extends string[] ? never : string |
   number extends string[] ? never : number |
   string[] extends string[] ? never : string[] |
= string | number | never 
= string | number

となる。頭ええな
Conditional Types!!!
参考:https://qiita.com/Quramy/items/b45711789605ef9f96de

まっきんとっしゅまっきんとっしゅ

https://github.com/type-challenges/type-challenges/blob/master/questions/189-easy-awaited/README.ja.md

問題

Promise ライクな型が内包する型をどのように取得すればよいでしょうか。 例えば、Promise<ExampleType>という型がある場合、どのようにして ExampleType を取得すればよいでしょうか。

解答

type MyAwaited<T extends Promise<any>> = T extends Promise<infer R> 
  ? (R extends Promise<any> ? MyAwaited<R> : R )
  : T;

PromiseにPromiseが含まれることを踏まえて再起的にMyAwaitedを使っている。

T extends U ? X : YみたいなやつをConditional Types とかいうらしい
参考:https://qiita.com/Quramy/items/b45711789605ef9f96de

とりあえずinferというのを知らんから調べる。

infer

inferはconditional typeのextendsの中でしか使われない。

なぜこれはOKで

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

なぜこれはNGなのか

type ReturnType<T> = T extends (...args: any[]) =>  R ? R : any;

NGである理由:Rが宣言されていないから

infer RとすることでTから型を推論している(infer:「推論する」の意味)

改めて解答に戻ると、
T extends Promise<infer R> ? (長い何か): TでTがPromise型じゃなければそのまま返す

(長い何か)の部分でTがPromise型だった時のことを考えている。

infer Rで取り出したPromise型の中身がさらにPromise型だったら再帰的にMyAwaited型に代入している。infer Rで取り出した型がPromiseでなければその値を返す。

すげーうまいこといってんな