Repository navigation
Type inference fails #41712
Copy link
Copy link
Closed
Labels
Fix AvailableA PR has been opened for this issueA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
Milestone
Description
TypeScript Version: 4.2.0-dev.20201127
Search Terms:
- typescript type inference
- typescript type not inferred correctly
- typescript mapped types
Code
interface INodeIO<T = any> {
value: T;
}
type IODefinition = Record<string, INodeIO>;
type IODefinitionValues<D extends IODefinition> = {
[K in keyof D]: D[K] extends INodeIO<infer T> ? T : never;
};
type CalcFunc<I extends IODefinition, O extends IODefinition> = (
inputs: IODefinitionValues<I>
) => IODefinitionValues<O>;
type NodeDefinition<I extends IODefinition, O extends IODefinition> = {
setup(): { inputs: I; outputs: O };
calculate?: CalcFunc<I, O>;
};
function defineNode<I extends IODefinition, O extends IODefinition>(def: NodeDefinition<I, O>) {
return def; // placeholder
}
// T1 is correctly identified as
// T1 = { hello: number; }
type T1 = IODefinitionValues<{ hello: { value: number } }>;
// T2 is identified as (inputs: IODefinitionValues<{ test: { value: number; };}>) => IODefinitionValues<{ ret: { value: boolean; }; }>
type T2 = CalcFunc<{ test: { value: number } }, { ret: { value: boolean } }>;
// This works as expected, Intellisense is working and I get type errors when using the wrong type
const calcFuncTest: T2 = (def) => ({ ret: Boolean(def.test) });
calcFuncTest({ test: 3 });
defineNode({
setup() {
return {
inputs: {
a: { value: 3 },
b: { value: "bar" }
},
outputs: {
c: { value: false },
d: { value: "foo" }
}
};
},
calculate(inputs) {
return {
c: inputs.v, // (1)
d: inputs.a, // (2)
};
}
});Expected behavior:
(1)should give an error, sinceinputs.vdoes not exist(2)should give an error, sinceinputs.ais anumber, whiledis astring
Actual behavior:
The code above compiles without errors. Also, Intellisense is not working at the calculate function inside defineNode.
Playground Link:
Link
Related Issues:
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Fix AvailableA PR has been opened for this issueA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
Activity
jcalz commentedon Dec 1, 2020
Could you provide a more minimal example?
Possibly related to #33042, #39838, #38872, maybe others?
newcat commentedon Dec 1, 2020
Tried shrinking it a bit, wasn't too successful (new playground link). But I replaced the domain-specific language with some generic terms so I hope it is a bit easier to understand. I'll explain it in more detail below.
Essentially, the code is about creating a
MappingComponent, which has some defined inputsIand some defined outputsO. In thesetup()method, these inputs and outputs are defined as aRecord<string, Wrapper>each. These wrapper instances can be seen as placeholders.The
mapfunction receives the values of the input placeholders (inputWrapper), so in this example it would be{ num: <some number>, str: <some string> }. It needs to return values for the output placeholders like this{ bool: <some boolean>, str: <some string> }.Similar to above, I expect
(1)should give an error, sinceinputs.nonexistentdoes not exist(2)should give an error, sinceinputs.numis a number, whilestrshould be a stringInterestingly, the outputs
Oare inferred correctly. So for example, returningbool: 3in the map function creates an error, since 3 is not a boolean.RyanCavanaugh commentedon Dec 1, 2020
I don't see any evidence of a bug here. The inference for a setup like this is extremely complex, but if the type parameters are set up correctly then you would see the expected errors.
Because there's a
Record<string,in the definition ofWrappedMap, you're not going to get an error oninputs.nonexistent, but it will produceunknownwhich triggers a downstream error.newcat commentedon Dec 2, 2020
I tried your code, however, I get errors on correct code now, because the values of
inputsare of typeunknownnow. Example of a correctmapfunction in the context above:Results in this error:
This may very well be a design limitation, because when the
mapfunction is not present, the type ofresis correctly inferred asAs soon as I write the mapping function, the type of
reschanges to: