Skip to content

Almost no type checking for mapped type with generic parameter #50558

@nrabinowitz

Description

@nrabinowitz

Bug Report

I am able to make a mapped type with a generic parameter that defines the keys of the new type. However, when the generic parameter is itself a generic, rather than a literal, type-checking fails almost completely.

May be a dupe of #49302

🔎 Search Terms

generic mapped type function

🕗 Version & Regression Information

Occurs in all of current release 4.7.4, current beta 4.8.0-beta, and current nightly.

⏯ Playground Link

Playground link with relevant code

💻 Code

type Model = {
    a: string;
    b: number;
}

type MappedModel<Suffix extends string> = {
    [K in keyof Model as `${K}${Suffix}`]: Model[K];
}

// Works as expected:
const foo: MappedModel<'Foo'> = { aFoo: 'test', bFoo: 42 };
// @ts-expect-error
const fooBad: MappedModel<'Foo'> = { bFoo: 'bar' };

function getModel<T extends string>(name: T): MappedModel<T> {
    // With a generic, there is almost no type-checking on assignment
    const okay: MappedModel<T> = 42;
    const okay2: MappedModel<T> = 'test';
    const okay3: MappedModel<T> = [1,2,3];
    const okay4: MappedModel<T> = false;
    const okay5: MappedModel<T> = {foo: 'bar'};

    // Only null and undefined error out
    // @ts-expect-error
    const bad: MappedModel<T> = undefined;
    // @ts-expect-error
    const bad2: MappedModel<T> = null;

    return okay;
}

// Consumers of the function get the correct output type
const model = getModel('Foo');
const str: string = model.aFoo;
// @ts-expect-error
const str2: string = model.bFoo;

🙁 Actual behavior

Within a function using the generic T, the type MappedModel<T> provides almost no type safety.

🙂 Expected behavior

Within a function using the generic T, the type MappedModel<T> should accurately protect against type errors in assignment or in the return value.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions