Description
TypeScript Version: 2.3
Code
type A = {
a: string
}
let a: A = {
a: 'a',
b: 11 // [0] error as expected: object literal can only specify known properties
}
let obj = {
a: 'a',
b: 11
}
let a2: A = obj // [1] no error
type B = A | {b: string}
let b: B = {
a: 'a',
b: 11 // [2] no error
}
Expected behavior:
There should be a way to make both marks [1] and [2] error, as [0] does.
Actual behavior:
[1] and [2] don't error - and there is no way to structure the code to enforce stricter checks like this.
The behavior in [0] is very fragile, and can lead one to a false sense of security, especially in cases like [2] (where 'b' is present but is of the wrong type). It would be incredibly useful to require the type to be matched exactly.
Motivation:
I think it would be useful to describe the problem I'm trying to solve rather than just proposing a solution.
I am trying to add a layer of type-safety to my db queries. As an example, mongdb has an _id
field that is of type ObjectID
. It's common to get such an id as part of an http request, in which case it is a string
, and forget to convert it into anObjectID
before using it in a query (in which case the query returns nothing).
I thought I'd create a union type of possible queries that we might send to a particular collection:
type Query = {
_id: 'ObjectID'
} | {
account_id: string
} | {
_id: 'ObjectID'
account_id: string
}
declare let findOne: (query: Query) => void
findOne({ _id: "I'm still a string! :(", account_id: "account_id" })
but, this doesn't provide the desired type safety as explained above, and it seems this is not something that TypeScript can help with.
Activity
mhegazy commentedon Jun 6, 2017
The first one is the intended design. TypeScript type system is structural, so it is OK to assign a value with more properties to one that expects less. think of
var a: Animal = dog;
should be allowed. there is one special rule though, for object literals we know there is no way for them to be aliased so any properties on the object, that are not required by the target are flagged as errors (e.g.let a: A = { a: 'a', b: 11 }
).The second issue is tracked by #12745.
mhegazy commentedon Aug 17, 2017
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.