microsoft / microsoft/TypeScript
Constrained generic types infer `never` on a function, even when the argument meets the constraints
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.4k
- Ø Merge
- 1 T. 19 Std.
- Gemergte PRs (30 T.)
- 117
Beschreibung
Bug Report
🔎 Search Terms
- inference of generic types fails with typed argument
- infer generic never
- constrained generic infers never
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about 4.3.2
⏯ Playground Link
Playground link with relevant code
💻 Code
type ValidKey = string | number | symbol;
/* The class ultimately being built */
class Test<T, I extends ValidKey & keyof T> {
idProp: I;
constructor(idProp: I) {
this.idProp = idProp;
}
}
interface WithId<T, I extends ValidKey & keyof T> {
idProp: I;
}
type IDableEntity<I extends ValidKey> = Record<I, ValidKey>;
class TestBuilder<T extends Record<ValidKey, any>> {
id<I extends ValidKey & keyof T>(idProp: I): this & WithId<T, I> {
return {
...this,
"idProp": idProp
};
}
}
function testBuilder<T>(): TestBuilder<T> {
return new TestBuilder<T>();
}
function build<
T extends IDableEntity<I>,
I extends ValidKey & keyof T>
(builder: TestBuilder<T> & WithId<T, I>): Test<T, I> {
return new Test<T, I>(builder.idProp);
}
interface IDable {
id: string;
}
const foo: TestBuilder<IDable> & WithId<IDable, 'id'> = testBuilder<IDable>().id('id');
const bar = build(foo);
/*
Argument of type 'TestBuilder<IDable> & WithId<IDable, "id">' is not assignable to parameter of type 'TestBuilder<IDableEntity<never>> & WithId<IDableEntity<never>, never>'.
Type 'TestBuilder<IDable> & WithId<IDable, "id">' is not assignable to type 'WithId<IDableEntity<never>, never>'.
Types of property 'idProp' are incompatible.
Type 'string' is not assignable to type 'never'.ts(2345)
*/
This also fails if I create a new type CompleteTestBuilder<T extends IDableEntity<I>, I extends ValidKey & keyof T> = TestBuilder<T> & WithId<T, I> that build accepts as an argument, or if I define CompleteTestBuilder as its own interface extends TestBuilder<T> { idProp: I}.
A simpler version that does NOT fail:
function build2<T>(builder: TestBuilder<T>): TestBuilder<T> {
return builder;
}
const baz: TestBuilder<IDable> = testBuilder<IDable>();
const qux = build2(baz); // qux: TestBuilder<IDable>
This version also does NOT fail:
function build3<T extends Record<ValidKey, any>>(builder: TestBuilder<T>): (t: T) => string {
return (t: T) => 'boo';
}
const quux = build3(baz); // quux: (t: IDable) => string
🙁 Actual behavior
The build call fails with the error message:
Argument of type 'TestBuilder<IDable> & WithId<IDable, "id">' is not assignable to parameter of type 'TestBuilder<IDableEntity<never>> & WithId<IDableEntity<never>, never>'.
Type 'TestBuilder<IDable> & WithId<IDable, "id">' is not assignable to type 'WithId<IDableEntity<never>, never>'.
Types of property 'idProp' are incompatible.
Type 'string' is not assignable to type 'never'.ts(2345)
🙂 Expected behavior
I would expect the build call to succeed, and types T and I to be inferred as IDable and "id", respectively. The argument type is already known and correct (it is even inferred correctly - the type assignment for foo is just to show that the type is correct). The types on the function should be able to match.
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit der verknüpften Playground-Reproduktion und dem generischen Inferenzverhalten in der build-Funktion. Verfolge, wie die Einschränkungen für T und I zu never führen, und überprüfe dann, dass der Aufruf build(foo) erfolgreich ist und T als IDable sowie I als "id" inferiert, ohne die einfacheren Beispiele zu beeinträchtigen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Bug
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 30/100