Closed
Description
Suggestion
π Search Terms
- typescript infer union type
β Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
β Suggestion
Adding a way to infer the correct type in a union using a value of its own key.
π Motivating Example
If I have the following type, it is a simple Union where we always have a type
key and we find a key
of the value of the type
.
type T1 = {
type: 'title',
title: string
} | {
type: 'checkbox',
checkbox: boolean
}
const properties: T1[] = [
{
type: 'title',
title: 'Hello world',
},
{
type: 'checkbox',
checkbox: false
}
]
properties.map(el => {
// By checking the value of the type key, the inference is done
if (el.type === 'title') return el[el.type]
// There is only one possibility in our union
return el[el.type]
})
properties.map(el => {
// Inference is not done and this does not work even if all types in our union match
return el[el.type]
})
π» Use Cases
I am querying an external API that returns me a list of properties:
{
"properties": {
"isActive": {
"type": "checkbox",
"checkbox": true
},
"email": {
"type": "email",
"email": "[email protected]"
},
"content": {
"type": "rich_text",
"rich_text": {
"plain_text": "Hello world",
"blocks": []
}
}
}
}
I want to normalize this data into:
{
"isActive": true,
"email": "[email protected]",
"content": "Hello world"
}
There are some specific property types like rich_text
where I need a specific normalization process.
And by default I simply want to return the value.
type PropertyTypes = 'email' | 'checkbox' | 'rich_text'
type PropertyDenormalizedValueMap = {
'email': string;
'checkbox': boolean;
'rich_text': {
plain_text: string,
blocks: any[]
}
};
type PropertyNormalizedValueMap = {
'email': string;
'checkbox': boolean;
'rich_text': string;
};
type PropertyObject<T extends PropertyTypes> = {
[key in T as string]: {
type: key;
} & {
[property in key]: PropertyDenormalizedValueMap[key];
};
}[T];
interface Normalizer<T extends PropertyTypes = PropertyTypes> {
normalize(data: PropertyObject<T>): PropertyNormalizedValueMap[T];
}
class RawNormalizer implements Normalizer<'email'|'checkbox'> {
normalize(data: PropertyObject<'email'|'checkbox'>): PropertyNormalizedValueMap['email'|'checkbox'] {
// By checking the `type` key it infers the Type
if (data.type === 'checkbox') return data[data.type];
// The only possible type in our union make this possible
return data[data.type]
}
normalize2(data: PropertyObject<'email'|'checkbox'>): PropertyNormalizedValueMap['email'|'checkbox'] {
// This is not possible as there is no inference done
return data[data.type]
}
}
class RichTextNormalizer implements Normalizer<'rich_text'> {
normalize(data: PropertyObject<'rich_text'>): PropertyNormalizedValueMap['rich_text'] {
return data.rich_text.plain_text
}
}