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

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

suke
June 04, 2024

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

TSKaigi 2024 After Talk

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