satisfies but for types [duplicate]
Asked Answered
S

1

8

TypeScript 4.9's satisfies operator is super handy, allowing narrowly typed values that still match a wide definitions.

type WideType = Record<string, number>;

const narrowValues = {
    hello: number,
    world: number,
} satisfies WideType;

Is there any way to define one type as satisfying another?

type WideType = Record<string, number>;

type NarrowType = {
    hello: 4,
    world: 5,
} satisfies WideType;

For types where you want very-specific values it's possible to go through a value to a type:

type WideType = Record<string, number>;

const narrowValues = {
  hello: 4,
  world: 5,
} satisfies WideType;

type NarrowType = typeof narrowValues;

But it gets a little clunky if you're trying to deal with anything more complex:

type TemplateType = `${number}-${number}`;
type UnionType = "FOO" | "BAR";

type WideType = Record<string, string>;

const narrowValues = {
  hello: "" as TemplateType,
  world: "" as UnionType,
  blah: "" as string
} satisfies WideType;

type NarrowType = typeof narrowValues;

Also it'd be great to be able to do this without creating any extra JS code.

Songwriter answered 30/5, 2023 at 17:47 Comment(2)
You could define a utility Satisfies type that acts this way, as shown here. Does that fully address your question? If not, what am I missing?Bozcaada
@Bozcaada Believe it does! Thanks!Songwriter
S
0

You can achieve the desired behavior using mapped types and conditional types in TypeScript:

type WideType = Record<string, string>;

type NarrowValues<T> = {
  [K in keyof T]: T[K] extends TemplateType<any, any> | UnionType<any> ? T[K] : T[K] extends string ? T[K] : never;
}[keyof T];

const narrowValues: NarrowValues<WideType> = {
  hello: "FOO" as TemplateType<any, any>,
  world: "BAR" as UnionType<any>,
};

We define a mapped type NarrowValues that iterates over the keys of the given type T. For each key, it checks if the corresponding value is a TemplateType or UnionType. If it is, it uses the value directly; otherwise, it uses the value as a string. Finally, we create an object narrowValues that satisfies the WideType while using more complex types for the values.

This solution doesn't require extra JavaScript code and works purely with TypeScript types. However, it may be less readable and more complex than using the satisfies operator, which is designed to simplify type-safe configuration in TypeScript

Shampoo answered 30/5, 2023 at 17:51 Comment(2)
this looks so combersome for such a simple task TS team should do something about it, it would be incredibly usefulHug
I agree this is not great at all. Typescript would absolutely benefit from the satisfies operator just being usable for types.Relief

© 2022 - 2024 — McMap. All rights reserved.