In TypeScript, I have a function that takes a generic object whose values are all an instance of a generic class (MyClass<T> in the code sample below). I want the return value to be an object with the same keys but whose types are the corresponding T types.
Using TypeScript's infer keyword I've gotten this to work; however, if one of the T's is a union with undefined then the undefined seems to be dropped.
How can I get the undefined to carry through to the type of the corresponding key in the returned object?
Code sample:
class MyClass<T> {
type = "MyClass";
}
type MyClassType =
| MyClass<string>
| MyClass<number>
| MyClass<string | undefined>
interface MyClassInstanceByName {
[name: string]: MyClassType
}
type ValueTypeByMyClassInstanceByName<T extends MyClassInstanceByName> = {
[P in keyof T]: T[P] extends MyClass<infer U> ? U : never
}
function transformer<T extends MyClassInstanceByName>(input: T):
ValueTypeByMyClassInstanceByName<T> {
throw new Error("not implemented");
}
function test() {
const result = transformer({
shouldBeString: new MyClass<string>(),
shouldBeNumber: new MyClass<number>(),
shouldBeStringOrUndefined: new MyClass<string | undefined>(),
});
const isAString: string = result.shouldBeString;
const isANumber: number = result.shouldBeNumber;
const isStringOrUndefined: string = result.shouldBeStringOrUndefined;
// The type of `result.shouldBeStringOrUndefined` above is inferred to be
// `string`, but I want it to be inferred as `string | undefined`.
}
I've tried a whole bunch of different permutations of the type declarations, but each time I get something that works it "drops" the undefined or produces something incorrect, like never. I also tried to understand the difference between an optional property (i.e. a field name suffixed with ?) and a property whose type is | undefined. I tried to figure out some magic to mark the properties with undefined in their type union as optional with ? but haven't quite figured that out.