TypeScript Version: 3.7.2
Search Terms:
Expected behavior:
let barGenerator: Generator<any, string, { name: string; } | { age: number; }>;
Actual behavior:
let barGenerator: Generator<any, string, { name: string; } & { age: number; }>;
Related Issues:
Code
function* Bar() {
let x: { name: string } = yield;
let y: { age: number } = yield;
return x.name + y.age;
}
let barGenerator = Bar();
// let barGenerator: Generator<any, string, { name: string; } & { age: number; }>;
let barResult = barGenerator.next();
barResult = barGenerator.next({ name: "Bar" }); // Error: Argument of type '[{ name: string; }]' is not assignable to parameter of type '[] | [{ name: string; } & { age: number; }]'.
barResult = barGenerator.next({ age: 40 });
console.log(barResult);
Output
"use strict";
function* Bar() {
let x = yield;
let y = yield;
return x.name + y.age;
}
let barGenerator = Bar();
//let barGenerator: Generator<any, string, { name: string; } & { age: number; }>
let barResult = barGenerator.next();
// Error: Argument of type '[{ name: string; }]' is not assignable to parameter of type '[] | [{ name: string; } & { age: number; }]'.
barResult = barGenerator.next({ name: "Bar" });
barResult = barGenerator.next({ age: 40 });
console.log(barResult);
Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"useDefineForClassFields": false,
"alwaysStrict": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"downlevelIteration": false,
"noEmitHelpers": false,
"noLib": false,
"noStrictGenericChecks": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"esModuleInterop": true,
"preserveConstEnums": false,
"removeComments": false,
"skipLibCheck": false,
"checkJs": false,
"allowJs": false,
"declaration": true,
"experimentalDecorators": false,
"emitDecoratorMetadata": false,
"target": "ES2017",
"module": "ESNext"
}
}
Playground Link: Provided
Only type that has both name and age can be assigned to both x and y.
See example
Only intersection satisfy both constraints but union would lead to a problem
let barResult = barGenerator.next();
barResult = barGenerator.next({ name: "Bar" });
barResult = barGenerator.next({ name: "Bar" }); // allowed by union, but not assignable to { age: number }
Only type that has both
nameandagecan be assigned to bothxandy.
See example
Only intersection satisfy both constraints but union would lead to a problemlet barResult = barGenerator.next(); barResult = barGenerator.next({ name: "Bar" }); barResult = barGenerator.next({ name: "Bar" }); // allowed by union, but not assignable to { age: number }
If x has type string and y has type number, then intersection will be never. And so, I can't use the generator at all.
function* Foo() {
let x: string = yield;
let y: number = yield;
return x + y;
}
let fooGenerator = Foo();
// let fooGenerator: Generator<undefined, string, never>
let fooResult = fooGenerator.next();
fooResult = fooGenerator.next("Foo"); // Error: Argument of type '["Foo"]' is not assignable to parameter of type '[] | [never]'
fooResult = fooGenerator.next(40); // Error: Argument of type '[40]' is not assignable to parameter of type '[] | [never]'
console.log(fooResult);
IMHO statically typing yield is impossible as soon as you start using different input types because TS can't enforce types order in general case.
In this case you can't rely on inferred type and need to add explicit annotation. It can be Generator<undefined, string, any> or more involved Generator<undefined, string, string | number> and type assertions
But this will be your responsibility to math expected and passed types at runtime.
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.
Most helpful comment
IMHO statically typing
yieldis impossible as soon as you start using different input types because TS can't enforce types order in general case.In this case you can't rely on inferred type and need to add explicit annotation. It can be
Generator<undefined, string, any>or more involvedGenerator<undefined, string, string | number>and type assertionsBut this will be your responsibility to math expected and passed types at runtime.