#How to define a type that enforces an object key to match a value

14 messages · Page 1 of 1 (latest)

latent vesselBOT
#
tickleme_pink#0

Preview:ts type ValidEnv<T extends Record<string, unknown> = Record<string, unknown>> = { [K: string]: T & {name: typeof K} } const env = { dev: { name: "dev", data: "data" }, prod: { //<----------------------------, name: "prodX", //<--- "prodX" !== "prod" ...

ionic whale
#

Not enough information to understand what you are asking for.

unreal orchid
#

The keys in env must be the same as the value in name

#

If the key is prod, the name is also prod

ruby patio
#

you'd need a cif for this

#

!:cif

latent vesselBOT
#
gerrit0#0
`!gerrit0:cif`:

If you want to both validate that a variable matches a specific type and also let TypeScript narrow the variable if possible, you may be able to use satisfies. If satisfies isn't flexibile enough, a constrained identity function is the best way to do this:

interface Foo {
  prop: string | number;
}

const foo = { prop: 123 } satisfies Foo
//    ^? const foo: { prop: number }
// errors if foo is not assignable to Foo

function createFoo<T extends Foo>(x: T) { return x }

const foo2 = createFoo({ prop: 123 })
//    ^? const foo2: { prop: number }
ionic whale
#

Alternatively you could omit the name entries, and run it through a function that adds them, and return a mapped type that includes them.

unreal orchid
#

I see, yea I'll try that approach

latent vesselBOT
#
sandiford#0

Preview:```ts
type Env<E extends Record<string, object>> = {
[K in keyof E]: {readonly name: K} & E[K]
} & {} // this & {} at the end expands the result type so it can be read more easily

const env = {
dev: {
data: "data",
},
prod: {
data: "data",
},
} as const
...```

unreal orchid
#

Yea that should work

#

The cast is quite unfortunate though

#

I'll keep it an identity function instead to avoid the cast.

ionic whale
#

Embrace the cast 🙂