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

組み込み型とライブラリの型から学ぶUnion Distributionの活用法

Avatar for suke suke
June 04, 2024

組み込み型とライブラリの型から学ぶUnion Distributionの活用法

TSKaigi 2024 After Talk

Avatar for suke

suke

June 04, 2024
Tweet

Other Decks in Programming

Transcript

  1. Union DistributionとDistributive Conditional Types type NonNullable<T> = T extends null

    | undefined ? never : T; type T1 = NonNullable<string | null> // NonNullable<string> | NonNullable<null> // string | never // string • Conditional Typesの条件部の左側にユニオン型が直接渡された場合、ユニ オン型の各要素に対して個別に条件が適用される特性 ◦ この特性をUnion Distribution(ユニオン分配)という • 条件部の右側にユニオン型が渡された場合は分配が発生しない
  2. Union DistributionとDistributive Conditional Types // Tは分配される type T1<T> = T

    extends string ? true : false // Tは分配されない type T2<T> = [T] extends [string] ? true : false // Tは分配され、Uは分配されない type T3<T, U> = T extends U ? true : false
  3. Union Distributionによって意図しない動作をする例 type IsString<T> = T extends string ? true

    : false   type T1 = IsString<string | number> type T1 = IsString<string> | IsString<number> // string | numberはstring型ではないため期待する結果は falseになる type T1 = true | false
  4. Union Distributionによって意図しない動作をする例 // 型引数をタプル型などでラップすることで分配を発生させない type IsString<T> = [T] extends [string]

    ? true : false type T1= IsString<string | number> // 分配が発生しないため [string | number] extends [string] ? true : false として評価される type T1 = false
  5. 両方の特性を利用した例 type IsUnion<T, U extends T = T> = ?

    チャレンジしてみてください! https://github.com/type-challenges/type-challenges/blob/main/questions/01097-medium-isu nion/README.md
  6. 両方の特性を利用した例 type IsUnion<T, U extends T = T> = IsNever<T>

    extends true ? false : T extends U ? [U] extends [T] ? false : true : false; type IsNever<T> = [T] extends [never] ? true : false type T1 = IsUnion<string | number> // IsNever<string> extends true ? false : string extends string | number ? [string | number] extends [string] ? false : true : false
  7. Exclude型 type Exclude<T, U> = T extends U ? never

    : T type T1= Exclude<'a' | 'b' | 'c', 'a' | 'b'> // 'c' // 以下のように展開される type T1 = Exclude<'a', 'a' | 'b'> | Exclude<'b', 'a' | 'b'> | Exclude<'c', 'a' | 'b'> type T1 = never | never | 'c' type T1 = 'c'
  8. Extract型 type Extract<T, U> = T extends U ? T

    : never type T1 = Extract<'a' | 'b' | 'c', 'a' | 'c'> // 'a' | 'c' // 以下のように展開される type T1 = Extract<'a', 'a' | 'c'> | Extract<'b', 'a' | 'c'> | Extract<'c', 'a' | 'c'> type T1 = 'a' | never | 'c' type T1 = 'a' | 'c'
  9. HasKey型 type HasKey<T, K extends Key> = IsNever<Exclude<K, Keys<T>>> type

    T1 = HasKey<{ foo: string, bar: string }, 'foo'> // true type T2 = HasKey<{ foo: string, bar: string }, 'foo' | 'hoge'> // false // IsNever<Exclude<'foo' | 'hoge', 'foo' | 'bar'>> // IsNever<'hoge'> // false https://github.com/react-hook-form/react-hook-form/blob/v7.51.5/src/types/path/common.ts#L376
  10. CheckKeyConstraint型 type CheckKeyConstraint<T, K extends Key, U> = K extends

    any ? EvaluateKey<T, K> extends U ? K : never : never type T1 = CheckKeyConstraint<{ foo: string, bar: number }, 'foo' | 'bar', string> // ‘foo’ https://github.com/react-hook-form/react-hook-form/blob/v7.51.5/src/types/path/common.ts#L307
  11. UnionToIntersection型 type UnionToIntersection<U> = ( U extends any ? (_:

    U) => any : never ) extends (_: infer I) => any ? I : never type T1 = UnionToIntersection<{foo: string} | { bar: number }> // { foo: string } & { bar: number } https://github.com/react-hook-form/react-hook-form/blob/v7.51.5/src/types/path/common.ts#L72 https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type/50375286#50375286