3

Let's say there is a function to create an object.

interface Params {
  name: string
}

const createTypedObject = (params: Params) => ({
  [params.name]: 1,
})

I create an object

const obj = createTypedObject({ name: 'test' })
// Type obj {[p: string]: number}

How to make object type be {test: number}?

1 Answer 1

3

TypeScript isn't great at inferring generic types from created objects, so you're going to have to use a type assertion:

const createTypedObject = <P extends Params>(params: P) => ({
  [params.name]: 1,
}) as {[K in P['name']]: number}

Also note that the type of object literal {name: 'test'} is {name: string}, so to get the correctly narrowed property type, you'll have to add an as const to the parameter:

const obj = createTypedObject({name: 'test'} as const)
// obj: {test: number}

Alternatively, you can make params readonly, which will let TypeScript infer the narrowed type for literal objects, even without as const:

const createTypedObject = <P extends Params>(params: Readonly<P>) => ({
  [params.name]: 1,
}) as {[K in P['name']]: number}

const obj = createTypedObject({name: 'test'})
//    obj: {test: number}

TypeScript playground

Sign up to request clarification or add additional context in comments.

2 Comments

YOu can get rid of as const assertion just by adding extra generic Name. See here. Then you don't need to make it readonly
@captain-yossarianfromUkraine That's a valid alternative solution indeed, but I would choose the simplicity of the Readonly over introducing an additional generic parameter and intersection.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.