简体   繁体   中英

TypeScript How to make String Union Type to a concrete Obnject Type?

how can i implement this:

type ActionNames = 'init' | 'reset';

type UnionToObj<U> = {/* TODO HERE */}

type Result = UnionToObj<ActionNames>;
// expect type Result to be `{ init: any, reset: any }`

i had written a implementation, but it not work correctly, it meets the union extends covariance problem:

type UnionToObj<U> = U extends string ? { [K in U]: any } : never;
type Result = UnionToObj<'init' | 'reset'>;
// expecting the type Result to be `{ init: any, reset: any }`
// but i got a union object: `{ init: any } | { reset: any }`
// how do i resolve it ?

main problem:

  1. string union type to object type
  2. union's covariance in ts extends clause.

This is a straightforward mapped type :

type UnionToObj<U extends PropertyKey> = { [K in U]: any }

type Result = UnionToObj<ActionNames>;
/* type Result = {
    init: any;
    reset: any;
} */

Here we are constraining U to be key-like instead of checking it via a conditional type. If you really want to do it that way, you can, with a solution like this:

type UnionToObj<U> = [U] extends [PropertyKey] ? { [K in U]: any } : never;

The difference between this and your version is that your version is unintentionally a distributive conditional type . Since you don't want union inputs to become union outputs, you need to prevent conditional type distribution by not having U extends... directly with a bare type parameter in the checked position. Wrapping the checked type in a one-tuple ( [U] extends... ) is enough to turn off union distribution.

Playground link to code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM