-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
False positive error report for enum and class instance type missing index signature, thus not assignable to object type with unknown
values.
#30977
Comments
unknown
values.
unknown
values.unknown
values.
unknown
values.unknown
values.
unknown
values.unknown
values.
We have always had a rule that permits assigning any non-primitive type to a type with an index signature of type Now, we have another rule that permits an object literal type to be assigned to a type with an index signature provided all property types of the object literal are assignable to that index signature. We permit this because we know object literal types are exact (i.e. there are no additional properties we don't know about). This is true for enum object types as well, so we should extend this rule to cover enum types. That would solve the first unexpected error in the OP example. But we can't extend the rule to cover classes since they're by design extensible (and therefore not exact). |
First thing@ahejlsberg I am excited about switching from In // This way we technically declare { [key: any]: TValues; },
// which we can't do literally, but this is out of scope
type Obj<TValues> = Record<any, TValues>; Now the main body: export function dir<T extends Obj<unknown>>(dict: T): T {
// some logging logic
const value = dict.foo;
value.someProp; // compile error, value is of `unknown` type which is great
return dict;
}
const classDict = dir(new class {}); // nah, class instance is not allowed since 3.5
const objDict = dir({}); // ok If we use If we use Do you have any solution to this? Second thingWhy do we get the following behavior? type TakeObj<T extends Obj<unknown>> = T;
interface EmptyInterface {}
type EmptyTypeAlias = {};
type t0 = TakeObj<EmptyTypeAlias>; // ok
type t1 = TakeObj<EmptyInterface>; // compile error ?? |
First, here's one example of why we needed to retire the rule that permits anything to be assigned to declare function foo<T>(x: Record<string, T>): T[];
declare function foo<T>(x: T[]): T[];
foo({ a: 1, b: 'abc' }); // (string | number)[]
foo([1, 'abc']); // (string | number)[] If we had kept the rule, the I think you can reasonably make the argument that the new behavior is the consistent one. Our intent has always been that the only thing assignable to a dictionary type (a type of the form
I think
See #14736 (comment). |
Interesting, I always thought it would be a union of all the properties of
It depends on what you consider a dictionary. Technically any instance of
I'd like to avoid that. But regarding that classes may have
Thanks for pointing out. According to the compromise, you make for object literal types it is very easy to trick yourself, because if you define |
You're right. The correct reason we infer
I agree, it is somewhat unfortunate to have this subtle difference between classes/interfaces and object type literals, but it's the best we've been able to come up with. |
Hmm, I know it's not the place for proposals but, did you consider implementing explicitly invariant types like I often miss such a feature when I am in a context where I can't be sure whether I can do |
In #31687 we fix this as much as we can. The type of an enum object now has implicit index signatures that make it assignable to |
@ahejlsberg this was confusing for me as well -- can you help the community understand some of the tradeoffs that went into it? In particular, at #14736 (comment) you mentioned the reason was "[so] that anything that applies to an inferred object literal type also applies to an explicitly specified object literal type". I'm wondering if it could be beneficial to revisit that, especially because there's already some precedent with typescript treating object literals differently than an equivalently-typed variable (the "Object literal may only specify known properties" check). If typescript changed its behavior to only treat actual object literals as not having extra properties, we'd fix the inconsistency/confusion between Thanks. |
TypeScript Version:
3.5.0-dev.20190410
, (v3.4.3
doesn't have this bug)Search Terms:
enum, class, assignable, index signature
Code
Expected behavior:
This code should compile with no errors.
Actual behavior:
Error near the definition of
e1
andcl1
:Playground Link:
This works well in the playground as it uses the stable version of
tsc
, but this bug appears in dev build. Klick me.Related Issues:
None.
The text was updated successfully, but these errors were encountered: