-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Use template literal type as object key #45541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Looks like a duplicate of #13948 and/or #21030. Your example is kind of complicated for what amounts to a demonstration of using a computed key of a template literal type, but if I use the "unionize" type from here to distribute records over unions, like this: type DistribRecord<K extends PropertyKey, V> = { [P in K]: { [Q in P]: V } }[K]
const kv = <K extends PropertyKey, V>(k: K, v: V): DistribRecord<K, V> => ({ [k]: v } as any) Then instead of return {
...kv(`${actionName}Success`, createActionCreator(`${name}_SUCCESS`)),
...kv(`${actionName}Error`, createActionCreator(`${name}_ERROR`)),
...kv(`${actionName}Done`, createActionCreator(`${name}_DONE`)),
} And then you get const x = createRequestAction("SET_AS_FAVOURITE")
x.setAsFavouriteDone // ExactActionCreator<"SET_AS_FAVOURITE_DONE", () => { type: "SET_AS_FAVOURITE_DONE"; }>
x.setAsFavouriteError // ExactActionCreator<"SET_AS_FAVOURITE_ERROR", () => { type: "SET_AS_FAVOURITE_ERROR"; }> |
Hi, yes, that's that I'am talking about. For now I figured out this problem like this: type Types = "Success" | "Error" | "Done"
type SnakeToCamelCase<S extends string> = S extends `${infer T}_${infer U}` ? `${Lowercase<T>}${Capitalize<SnakeToCamelCase<U>>}` : Lowercase<S>
type Output<T extends string> = {
[key in `${SnakeToCamelCase<T>}${Types}`]: ExactActionCreator<
T,
() => {
type: T
payload: any
}
>
} And function looks like this: const createDeoxRequestAction = <T extends string>(name: T): Output<T> => {
const actionName = name
.split("_")
.map((item, i) => {
if (i === 0) {
return item.toLowerCase()
}
return item.charAt(0).toUpperCase() + item.slice(1).toLowerCase()
})
.join("") as SnakeToCamelCase<T>
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return {
[`${actionName}Success`]: createActionCreator(`${name}_SUCCESS`),
[`${actionName}Error`]: createActionCreator(`${name}_ERROR`),
[`${actionName}Done`]: createActionCreator(`${name}_DONE`),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any
} And that work properly, so if it's duplicated topic - I'm closing :) Thanks for your help @jcalz ;) |
Suggestion
Use template literal type as a key in object
π Search Terms
template literal string as object key
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Hello, I have a problem and maybe this thing will be a good feature. I would like to use template literal types as a key in for example interface. Let me show an example.
π Motivating Example
I've made a
ActionStringType
and for example:I was trying to make a action generator in redux and I found a problem where I can't type keys in object that
createRequestAction
returns. So this type is working fine but TS is still not seeing the names (keys of object) of action creators.And for example now something like
...createRequestAction("SET_AS_FAVOURITE")
returns:I want to change this
[x: string]
to something like S1 type returns.So, that is my idea, idk how to implement this, maybe it's impossible for now, but i think it will be a good feature. Let me know your thoughts, maybe I'm doing something wrong :)
π» Use Cases
The text was updated successfully, but these errors were encountered: