I was testing various typescript types till I came upon the following situation.
Why can Record<string, any>
equal Functions?
type C = { [key: string]: any } // Record<string, any>;
const C0: C = undefined // error
const C1: C = null // error
const C2: C = 2 // error
const C3: C = 'hello world' // error
const C4: C = { foo: 'bar' } // ok
const C5: C = () => undefined // ok
Yet Records<string, unknown>
can't?
type B = { [key: string]: unknown } // Record<string, unknown>;
const B0: B = undefined // error
const B1: B = null // error
const B2: B = 2 // error
const B3: B = 'hello world' // error
const B4: B = { foo: 'bar' } // ok
const B5: B = () => undefined // error
CodePudding user response:
Record<string, any>
is special cased for assignability and it basically means any object type. This is explained in this GitHub issue
Normally the source type must have an index signature if the target type does, but for : any there's really nothing implied by this (every property must match any, by definition), so we made [s: string]: any a no-op for assignability reasons. This enabled some patterns that didn't work before:
function doSomething(obj: { [s: string]: any}) {
// ...
}
const obj = { a: 1, b: 2 };
// WAS ERROR: 'obj' lacks index signature
doSomething(obj);
This creates some undesirable assignability in some cases, so we didn't apply this rule to : unknown so that you could pick which behavior you wanted.