-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
TypeScript Version: 2.6.1
Code
This snippet is a based on a problem discovered when using my library, runtypes, with TypeScript 2.6 and --strictFunctionTypes. I've stripped it down to the following minimal repro:
const Foo = Obj({ foo: Num })
// ^^^^^^^^^^^^
// error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype<any>; }'.
// Property 'foo' is incompatible with index signature.
// Type 'Num' is not assignable to type 'Runtype<any>'.
// Types of property 'constraint' are incompatible.
// Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
// Types of property 'underlying' are incompatible.
// Type 'Num' is not assignable to type 'Runtype<any>'.
interface Runtype<A> {
constraint: Constraint<this>
witness: A
}
interface Num extends Runtype<number> {
tag: 'number'
}
declare const Num: Num
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
underlying: A,
check: (x: A['witness']) => void,
}Expected behavior:
Should type check.
Actual behavior:
It fails with the error shown in the comment.
Commentary
The error is strange; it begins and ends with this:
Type 'Num' is not assignable to type 'Runtype<any>'
But that's clearly not true, as evidenced by the fact that this works:
const wat: Runtype<any> = NumAnd bizarrely, if you make that declaration at the top of the file it will make the error go away! But only if you declare wat before Foo. If you declare wat after Foo, both Foo and wat are flagged with Type 'Num' is not assignable to type 'Runtype<any>'.
There are a number of other ways to make the error go away, none of which I understand any better:
- change any of
Num,ObjorConstraintto be atypeinstead of aninterface, e.g.type Num = Runtype<number> & { tag: 'number' }
- delete any of the fields:
tag,underlyingorcheck - change the signature of
checktocheck(x: A['witness']): void,