Skip to content
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

object literal property check inconsistent #16284

Closed
dlants opened this issue Jun 6, 2017 · 2 comments
Closed

object literal property check inconsistent #16284

dlants opened this issue Jun 6, 2017 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@dlants
Copy link

dlants commented Jun 6, 2017

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.

@mhegazy
Copy link
Contributor

mhegazy commented 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 mhegazy added the Duplicate An existing issue was already created label Jun 6, 2017
@mhegazy
Copy link
Contributor

mhegazy commented 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.

@mhegazy mhegazy closed this as completed Aug 17, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

2 participants