Description
I would like the ability to do string manipulation within my types. Examples could include stripping out properties that match a regex/prefix/suffix or mapping types to include additional properties derived from the keys of existing ones.
Some examples might explain best:
Example
declare loadThings<T>(T): PossiblyLoading<T>;
declare getTheBar(id: number): Loader<Bar>;
let foo: { bar: Bar | undefined, barLoading: boolean };
foo = loadThings({
bar: getTheBar(55302),
});
Where PossiblyLoading
might be implemented like so:
type PossiblyLoading<T> = {
[K in keyof T]: UnwrapLoader<T[K]>;
[(K in keyof T) + "Loading"] + ?: boolean
}
Both should work because the string literal is easily detectable vs the token ?
.
This should also work with generic types that extend string:
type MutateProps<T, P extends string, S extends string> = {
[P + (K in keyof T) + S] + ?: T[K]
}
But I would also want to be able to use these within conditional types, using standard javascript functions:
type RemovePrefixed<T, P extends string> = {
[K in keyof T]: K.startsWith(P) ? never : T[K];
}
And we could even remove a prefix:
type RemovePrefix<T, P extends string> = {
[(K in keyof T).startsWith(P) ? K.slice(P.length) : K]: T[K];
}
If we wanted to avoid getting too crazy with function calls we could perhaps do it like this:
type RemovePrefixed<T, P extends string> = {
[(P + infer K) in keyof T ? never : K]: T[K];
}
type RemovePrefix<T, P extends string> = {
[(P + infer K) in keyof T ? K : never]: T[P + K];
}
Although I think the one that supports a subset of string function is more broadly useful. For example, we could probably do something around indexing into "foo.bar.baz" and resolve the innermost type of baz.
cc/ @ahejlsberg @mhegazy