When it comes to mapping object values with all primitive types, the process is quite straightforward:
type ObjectOf<T> = { [k: string]: T };
type MapObj<Obj extends ObjectOf<any>> = {
[K in keyof Obj]: Obj[K] extends string ? Obj[K] : 'not string';
};
type Foo = MapObj<{
a: 'string',
b: 123,
}>; // Foo is { a: 'string', b: 'not string' }
However, things get tricky when unions are involved as object values in TypeScript:
type AllPaths = '/user' | '/post';
type Props<Path extends AllPaths> = MapObj<{
path: Path,
}>;
function Fn<Path extends AllPaths>({ path }: Props<Path>) {
const path2: AllPaths = path;
}
Encountering the error:
Type 'Path extends string ? Path : "not string"' is not assignable to type 'AllPaths'.
Type 'Path | "not string"' is not assignable to type 'AllPaths'.
Type '"not string"' is not assignable to type 'AllPaths'.
Type 'Path extends string ? Path : "not string"' is not assignable to type '"/post"'.
Type 'Path | "not string"' is not assignable to type '"/post"'.
Type 'string & Path' is not assignable to type '"/post"'.
Even though each member of the union is a string, the output of MapObj
does not remain as unions of strings. How can this issue be resolved?