Closed ulrichb closed 3 years ago
TY2
in _BAD
isn't doing anything. The signature should be written as:
funcParamsWithConstraint_BAD<TX2>(
funcX: GenericFunc<TX, TX2>, funcY: GenericFunc<TY, Y<TX2>>,
useX2: (x: TX2) => void,
) {
wrap(funcX); wrap(funcY);
}
This works as expected.
@RyanCavanaugh Okay, maybe I oversimplified the repro sample. I updated it (now indeed using TY2
).
The real code is a fluent API, where I need the type inference and the TY2 extends Y<TX2>
constraint.
@RyanCavanaugh Also added YDerived
to motivate TY2
better.
@RyanCavanaugh Any news on this?
I have now a second but much easier sample using a conditional type instead of a generic constraint:
type GenericFunc<TA, TB> = (x: TA) => TB;
class GenericFuncHolder<TA, TB> {
constructor(readonly func: GenericFunc<TA, TB>) { }
}
function wrap<TA, TB>(func: GenericFunc<TA, TB>) { return new GenericFuncHolder(func); }
//
export type PropertyToTypeName<TProperty> =
TProperty extends string | undefined ? "text" :
TProperty extends number | undefined ? "number" :
never;
function withFunc<TProperty>(
func: GenericFunc<string, TProperty>, typeName: PropertyToTypeName<TProperty>) {
console.log('func points to', typeName);
}
function withHolder<TProperty>(
holder: GenericFuncHolder<string, TProperty>, typeName: PropertyToTypeName<TProperty>) {
console.log('holder points to', typeName);
}
withHolder(wrap(x => x.length), "number"); // works fine
// emits TS2345: Argument of type '"number"' is not assignable to parameter of type 'never'
withFunc(x => x.length, "number");
Playground link%3B%20%2F%2F%20works%20fine%0D%0A%0D%0A%2F%2F%20emits%20TS2345%3A%20Argument%20of%20type%20'%22number%22'%20is%20not%20assignable%20to%20parameter%20of%20type%20'never'%0D%0AwithFunc(x%20%3D%3E%20x.length%2C%20%22number%22)%3B)
... like in the sample above the problem is that in the withFunc
-case TProperty
infers to {}
which you can see when adding TProperty extends {} ? "[is empty object]"
to the conditional type.
One more observation: When adding TProperty extends string | number
constraints in the second example it works (also for withFunc
). It seems that the inference works correctly because it cannot infer down to {}
.
I feel like I'm missing something, because this example really shouldn't error, but has since 2.8
type TypeName<T> = T extends number ? "number" : "something else";
function fn<T>(func: (x: string) => T, p: TypeName<T>): void { }
// Error
fn(x => x.length, "number");
The sample above now produces a crash in the LS in the Playground...
Uncaught Error: Cannot read property 'kind' of undefined
TypeError: Cannot read property 'kind' of undefined
at tE (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at Mh (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at Object.getTypeAtLocation (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at i (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at Object.getCodeActions (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7
at Object.f.flatMap (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at Object.e.getFixes (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7
at Object.f.flatMap (unpkg.com/@typescript-deploys/monaco-editor@3.8.0-dev.20191026/min/vs/language/typescript/tsWorker.js:7)
at editor.main.js:38
TypeScript Version: 3.0.0-dev.20180607 and 2.9.1
Search Terms: type inference generic constraint function callback accessor
Code
(Sorry for the long repro, it's the simplified version of a production issue and the inference issue seems to be a very special case.)
Expected behavior: Type inference works for
funcParamsWithConstraint_BAD
as it works forholderParams
andfuncParamsWithoutConstraint
. It seems that the generic constraint ofTY2
narrowsTX2
to{}
, but this works when usingwrap()
on the call site. Which is the reason, why I would expectfuncParamsWithConstraint_BAD
to work just fine.Actual behavior: "TS2339: Property 'xProperty' does not exist on type '{}'" in the last line.
Playground Link: Playground Link%20%7B%0D%0A%20%20%20%20%20%20%20%20use(holderX.func(this.x)%2C%20holderY.func(this.y))%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20funcParamsWithoutConstraint%3CTX2%2C%20TY2%3E(%0D%0A%20%20%20%20%20%20%20%20funcX%3A%20GenericFunc%3CTX%2C%20TX2%3E%2C%20funcY%3A%20GenericFunc%3CTY%2C%20TY2%3E%2C%0D%0A%20%20%20%20%20%20%20%20use%3A%20(x%3A%20TX2%2C%20y%3A%20TY2)%20%3D%3E%20void%2C%0D%0A%20%20%20%20)%20%7B%0D%0A%20%20%20%20%20%20%20%20use(wrap(funcX).func(this.x)%2C%20wrap(funcY).func(this.y))%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20funcParamsWithConstraint_BAD%3CTX2%2C%20TY2%20extends%20Y%3CTX2%3E%3E(%0D%0A%20%20%20%20%20%20%20%20funcX%3A%20GenericFunc%3CTX%2C%20TX2%3E%2C%20funcY%3A%20GenericFunc%3CTY%2C%20TY2%3E%2C%0D%0A%20%20%20%20%20%20%20%20use%3A%20(x%3A%20TX2%2C%20y%3A%20TY2)%20%3D%3E%20void%2C%0D%0A%20%20%20%20)%20%7B%0D%0A%20%20%20%20%20%20%20%20use(wrap(funcX).func(this.x)%2C%20wrap(funcY).func(this.y))%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0A%0D%0Aconst%20genericClassTarget%20%3D%20new%20GenericTarget%20(new%20X()%2C%20new%20Y%3CX%3E())%3B%0D%0A%0D%0A%2F%2F%20Type%20inference%20works%20when%20having%20the%20constraint%20but%20using%20%60wrap()%60%20on%20the%20call%20site%3A%0D%0AgenericClassTarget.holderParams(wrap(x%20%3D%3E%20new%20X())%2C%20wrap(y%20%3D%3E%20new%20YDerived%3CX%3E())%2C%0D%0A%20%20%20%20(x2%2C%20y2)%20%3D%3E%20console.log(x2.xProperty%2C%20y2.yDerivedProperty))%3B%0D%0A%0D%0A%2F%2F%20Type%20inference%20works%20without%20the%20%60TY2%60%20constraint%3A%0D%0AgenericClassTarget.funcParamsWithoutConstraint(x%20%3D%3E%20new%20X()%2C%20y%20%3D%3E%20new%20YDerived%3CX%3E()%2C%0D%0A%20%20%20%20(x2%2C%20y2)%20%3D%3E%20console.log(x2.xProperty%2C%20y2.yDerivedProperty))%3B%0D%0A%0D%0A%2F%2F%20Type%20inference%20doesn't%20work%2C%20TSC%20emits%20%22TS2339%3A%20Property%20'xProperty'%20does%20not%20exist%20on%20type%20'%7B%7D'%22%0D%0AgenericClassTarget.funcParamsWithConstraint_BAD(x%20%3D%3E%20new%20X()%2C%20y%20%3D%3E%20new%20YDerived%3CX%3E()%2C%0D%0A%20%20%20%20(x2%2C%20y2)%20%3D%3E%20console.log(x2.xProperty%2C%20y2.yDerivedProperty))%3B%0D%0A)
EDIT: Extended repro to make it more realistic.