如何通过判别属性从联合类型中获取对应类型及实现映射?
Absolutely! You can absolutely pull the exact type from your discriminated union using its tag discriminant property, and TypeScript gives you clean tools to build the tag-to-type mapping you want. Let's walk through this with concrete examples.
First, let's define the union and its member types to match your scenario:
// Define the individual tagged types interface Foo { tag: 'foo'; fooSpecific: string; } interface Bar { tag: 'bar'; barSpecific: number; } interface Baz { tag: 'baz'; bazSpecific: boolean; } // The discriminated union type Thing = Foo | Bar | Baz;
1. Extract a Single Type by Tag
To get the type corresponding to a specific tag value, TypeScript's built-in Extract utility type is perfect. It filters the union to only include members that match the condition you specify:
// Create a helper type that takes a tag and returns the matching type type ThingByTag<T extends Thing['tag']> = Extract<Thing, { tag: T }>; // Usage: Grab the exact type for any tag type FooType = ThingByTag<'foo'>; // Resolves to Foo type BarType = ThingByTag<'bar'>; // Resolves to Bar
How this works: Thing['tag'] gets all possible tag values from the union ('foo' | 'bar' | 'baz'), and Extract<Thing, { tag: T }> picks only the union member where the tag property equals T.
2. Build a Full Tag-to-Type Mapping
To create a complete mapping of all tags to their corresponding types (the mapping type you mentioned), you can combine the helper above with a mapped type:
// Map every tag in the union to its matching type type ThingMap = { [Tag in Thing['tag']]: ThingByTag<Tag>; }; // Now you can access types directly via their tag key type FooFromMap = ThingMap['foo']; // Foo type BazFromMap = ThingMap['baz']; // Baz
This mapped type iterates over every possible tag value from the union, and assigns each tag to the type you extracted with ThingByTag.
Alternative: Custom Conditional Type (Without Extract)
If you want to avoid using the built-in Extract utility, you can write a custom conditional type to achieve the same result:
type ThingByTagCustom<T extends Thing['tag']> = Thing extends { tag: T } ? Thing : never; // This works identically to the Extract version type BarTypeCustom = ThingByTagCustom<'bar'>; // Bar
This conditional type checks each member of the union to see if its tag matches T, and returns that member if it does.
All these approaches work reliably as long as your union is properly discriminated (each member has a unique literal tag property, which you confirmed is the case here).
内容的提问来源于stack exchange,提问作者Peter Hudec

