I'm trying to create a mapped type that would force a class to implement a set of properties based on some object type. Basically when object type is extended, class needs to be extended as well.
type SomeObjectType = {
a?: {/* ... */},
b?: {/* ... */},
c?: {/* ... */}
}
type SomeMappedType = {
[K in keyof SomeObjectType]: SomeGenericClass<K>
}
class SomeClass implements SomeMappedType {
a?: SomeGenericClass<'a'>;
b?: SomeGenericClass<'b'>;
c?: SomeGenericClass<'c'>;
}
The issue with the above code is, that since all object properties in SomeObjectType
are optional ?
it doesn't force the class to implement them.
I tried to use | undefined
but it doesn't work either. Only way to make it work is to get rid of ?
using -?
:
type SomeMappedType = {
[K in keyof SomeObjectType]-?: SomeGenericClass<K>
}
class SomeClass implements SomeMappedType {
a: SomeGenericClass<'a'>;
b: SomeGenericClass<'b'>;
c: SomeGenericClass<'c'>;
}
But then I can't store undefined
values to those properties.
Is this what you need? I used Array
for demonstration purposes.
type SomeObjectType = {
a: {/* ... */},
b?: {/* ... */},
c?: {/* ... */}
}
type RequiredLiteralKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never :
{} extends Pick<T, K> ? never : K]: 0 }
type OptionalLiteralKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never :
{} extends Pick<T, K> ? K : never]: 0 }
type SomeMappedType = {
[K in RequiredLiteralKeys<SomeObjectType>]: Array<K>
} & {
[K in OptionalLiteralKeys<SomeObjectType>]-?: Array<K> | undefined
}
class SomeClass implements SomeMappedType {
a!: Array<'a'>;
b!: Array<'b'>;
c!: undefined // will error if c is missing but undefined still works
}
All required properties stay required and all optional will be converted to Array<T> | undefined
.