microsoft / microsoft/TypeScript
Constrained generic types infer `never` on a function, even when the argument meets the constraints
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
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.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia dalla riproduzione collegata in Playground e dal comportamento di inferenza generica nella funzione build. Traccia come i vincoli su T e I producano never, quindi verifica che la chiamata build(foo) abbia esito positivo e inferisca T come IDable e I come "id" senza compromettere gli esempi più semplici.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- typescript
- Ambito
- compilers
- Tipo di issue
- Bug
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 30/100