-
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
Unable to void object keys using strictNullChecks
option
#8904
Comments
Are you sure you don't want a union type |
@Arnavion Why would a union be useful here? I don't think that would change anything. I want to be able to use the intersection to override properties of the initial object with valid assignments - in this case, resetting them back to void (not required). Edit: For example, I have one larger interface and I want to specify that everything other than this property is required. interface Foo {
a: string
b: string
c: string
d: string
...
}
// Use without `c`
function addsC (foo: Foo & { c: void }) {
foo.c = 'test'
} This is a pretty common pattern for me - where I may have a function that defines the ideal object and then some of it can be populated at a later time. For instance, a database model that is currently two objects but after the first object is stored it adds the |
But really, the type doesn't make sense. You're trying to do this: var x: string & undefined;
x = "foo";
x = undefined; The compiler correctly complains about both the assignments, since neither (Ideally it would complain about the type declaration itself, but it doesn't at the moment.) It sounds to me like you're actually looking for a way to take an interface of normal properties and produce an interface that has a subset of properties missing or optional, like subtraction types or something like Flow's type operators (examples here). So hypothetically where function addsC (foo: (Foo \ { c: string }) & { c?: string }) {
foo.c = 'test'
} or function addsC (foo: Foo \ { c: string }): Foo {
return { ...foo, { c: 'test' } };
} |
@Arnavion Actually, this works on current TypeScript and any nightly - it's only appears if you enable |
Also, I'm not trying to do Edit: That's not to say subtraction wouldn't be useful. I'm trying to point out an inconsistent behaviour with |
Of course it works currently without And |
Good point. Can you point me to the section talking about the primitive intersection behaviour inside of interfaces? I'd love to understand it better, my understanding of it is currently only intuitive which I would have imagined it's intersected at each property only (not deep) and Edit: I did the tests and understand the intersection of properties (just used |
we did not have i believe @Arnavion's recommendation is better here. so +1 to |
@mhegazy Make sense. Would it be reasonable to make a request that the |
interestingly this works today: var o1 : { x: string } | { x: undefined } = {}; //Fail
var o2 : { x: string } | { x?: undefined } = {}; //OK |
|
Good to know! Shouldn't Would be cool to have an improved intro on intersection/union and how to think out it 😄 |
|
Makes sense, I like it. Should be written down in an intersection/union docs page, this is pretty useful information. I'm going to close this for now. Eventually, I'm guessing, there'll need to be an optional type that doesn't also allow it to be |
Actually, through all this, I just realised it didn't actually answer the question. It still feels inconsistent. Is there somewhere I can read about the intersection and union type implementation and understand why properties inside the intersection don't end up "overriding" with more specific/assignable types instead creating nested intersection types? I can't actually use the union type discussed above (because, really, it's just made any value valid), but surprisingly you can't also do |
For example, this: interface Foo {
point: {
x: number
y: number
}
}
interface Bar {
point: {
// x: number
// y: number
z: number
}
}
const x: Foo & Bar = { point: { x: 1, y: 1, z: 1 } } I just get |
Missed this in the above comment:
Edit: Actually, I'm just going to assume none of this works and the advice is "don't do it". Still, I'd like to understand it better. Should these be errors at the intersection time, at the usage time, should nested intersect as the original comments explained? |
Your example is valid. It's a bug in 1.8.10 that causes it to be rejected. The bug is fixed in master. |
For two types If you imagine types as sets, then the union type is the union of the two sets, and the intersection type is the intersection of the two sets. That is where the names come from. Say you have type A = { x: string };
let a: A = { x: "x" };
type B = { x?: string };
let b: B = {};
type U = A | B;
let u: U;
u = a; // Valid
u = b; // Valid
type I = A & B;
let i: I;
i = a; // Valid
i = b; // Invalid Since Since In fact, |
Taking your original example type A = { x: string };
type B = { x: undefined };
type I = A & B; What kind of values are valid type T = /* something that's both a string and undefined */
type I = { x: T }; What's So It's not possible to have a value that is both a Consider the union type So |
Cool, thanks! I definitely should have run the latest checks on |
TypeScript Version:
Nightly
Code
Expected behavior: Works. Even better, it would allow me to call it without
userId
set at all.Actual behavior:
Edit: In case someone misses it in the title, enable
strictNullChecks
on the nightly releases.Edit 2: This seems like a big deal since the recommended way of dealing with
Object.create(null)
is this.Edit 3: I did also test replacing
void
withundefined
, to the same result.The text was updated successfully, but these errors were encountered: