Skip to content

Generic type inference is lost when partially specified #39008

@davidkpiano

Description

@davidkpiano

TypeScript Version: 3.7+ (including 4.0 Nightly)

Search Terms:

generic inference object restriction constraint

Code

// Restrict `initial` to be `keyof TStates`
interface Config2<T, TStates extends { [key: string]: any } = any> {
    context: T;
    states: TStates;
    initial: keyof TStates;
}

// Can't partially specify <T, TStates>, so default to any
function config2<T, TStates = any>(config: Config2<T, TStates>) { }

config2({
    context: { count: 0 },
    states: { foo: {}, bar: {} },
    initial: 'foo' // ✅ Properly checked!
    // initial: 'anything' // will not compile as expected
});

config2<{ count: number }>({
    context: { count: 0 },
    states: { foo: {}, bar: {} },
    initial: 'anything' // ❌ improperly allowed
});

Expected behavior:

In the above code, TStates should still be inferred to { foo: {}, bar: {} } so that .initial can be restricted to keyof TStates, which is 'foo' or 'bar' only. This works when no generic types are specified.

The goal is to express restriction/constraint within an object, which the above example shows: .initial should be restricted to a key of .states.

Actual behavior:

When 1 (or more) generic types are specified, the rest are "forced" to their defaults (any in this case), so inference is lost. In the above code, initial: 'anything' should cause a type error.

Playground Link: https://www.typescriptlang.org/play/?ts=4.0.0-dev.20200609&ssl=39&ssc=4&pln=18&pc=1#code/PTAEDkHtQJwUwM4BcYEsDGTWQHYChUck4YAzAQ3TlAGFdTUBzARgB4AVAPlAG89QBodLmIAPJAC5Q7ANz9BycsQRS+g9aADaAazgBPKcjQ5GAXSnkceueoC+NwYVRZyAG0MpCjObbx5SAK44mNg4QvRMbFwAFMI4DIxSdPGRHJwAlLygvnhxCczRaoJxYpJZwkFlAAzZADTyAorKqqCkkJCqtrWgAEbkMJ11DaBOLu6gAOSWekgAFl4ToCCgjJBuhrOQAa4AJqA4kEi91G6ukADucDt4tulyeMsASoiemKAABqOobu+gSNA9ajvXR6SCkaQAZSQSkQ7wIRBIFCotAijAATBxuuwoTCEKA4OI4DgdnieFoQR5jGYLFZsqAALygabcIoCEoEsqyYZNRBSbHQ5QOARfdagEFgyECxA+PzLGiWCZHAAO-TGrj0oAQSrg6FQpA1mMluM43QQ0B2cAo2yO-yZVn8QRCuHCKXRhv5uIZdr0nFiqKSqIx7CxOOUGSyOTyTDRhWG7PELQqRCkNS63KlKiybQ6vC6vX6gzT6hF4wm2cWy0AoOSgAAKMEg2pg6qEsx1uh2AEJhssS1IplY5gslmBzqhXK59odwgBbJVjk54gnazBXG53PxRt1kpNlHABaeAmDZX2sl2lRNbZOgVP1dQ8zNk7Odbp9Aa5obFnDOb6l6aDkwVmAgAy5JqmzbHsBxHICTLjhcq63DIQA

Related Issues: No, but here's a related link: https://stackoverflow.com/questions/54664214/typescript-relate-to-own-property-in-type

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