Skip to content

Support satisfies as a constraint on a function's generic type parameterΒ #58031

Closed as not planned
@rsslldnphy

Description

@rsslldnphy

πŸ” Search Terms

"satsifies", "satisfies generic parameter".

i found two similar/related feature requests, but they felt different enough to warrant being a separate feature request:

βœ… Viability Checklist

⭐ Suggestion

Currently, from what I can tell, is not possible to mimic the behaviour of satisfies on a function's generic type parameter - i.e. to define a function with a generic parameter that allows inference of a literal type that conforms to that generic parameter, while still benefitting from excess property checking. Because the only option for a generic type parameter is extends, there's no way (that I can see) to prevent extra keys in the inferred generic type.

πŸ“ƒ Motivating Example

A bare bones example of what this change would make possible:

type Foo = { a: number };

const foo = <T extends Foo>(x: T) => x;

foo({ a: 1, wrong: 2 }) // typechecks, but i don't want it to

foo({ a: 1, wrong: 2} satisfies Foo) // causes the type error i want

What I would really like to be able to write:

type Foo = { a: number };

const foo = <T satisfies Foo>(x: T) => x;

foo({ a: 1, wrong: 2 }) // causes the type error i want

πŸ’» Use Cases

  1. What do you want to use this for?

The reason I want this functionality is that I'm writing an ORM and would like to restrict the keys passed to the create function to only the keys present in the model. To be clear I do not need a runtime check and any extra keys actually in the model are fine. The reason I want this feature is to provide a good experience when writing code like this with literal types:

class DB<Models extends BaseModels> {
    public async create<
        M extends ModelName<Models>,
        P extends CreateParams<Models, M>,
    >(m: M, params: P): Promise<CreateResult<Models, M, P>> {
        // ...omitted for brevity
    }
    // ...omitted for brevity
}

db.create("post", {
    data: {
        title: "hello",
        content: "it me",
        authorId: uuid.v4(),
        // @ts-expect-error field does not exist
        wrong: 2,
    },
    returning: ["id"],
// this causes a type error if `satisfies` is used, but does not cause a type error if it is not
} satisfies CreateParams<typeof db.models, "post">);
  1. What shortcomings exist with current approaches?

It is only possible to use satisfies at the call site of a function, and must be used at every call site, rather than being specified as part of the function's generic type parameter.

  1. What workarounds are you using in the meantime?

I have not been able to find a workaround. If there is one, I would be very happy to hear it! If not I think the only option is to use satisfies at every call site.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions