Description
Bug Report
If you have a class along the lines of:
class User {
constructor(
public uid: number,
public password: string // sensitive info
) { }
get score(): number {
return 10; // example code - imagine having to fetch something a little more complex
}
}
If we then want to destructure a User
object (e.g. returning a client-friendly basic object from a server), we first declare a type:
type UserClient = Omit<User, 'password' | 'score'>;
We pass score
to the Omit
here because, as we're using destructing, only basic properties will be returned, not any getters. We can then create our method:
toClient(): UserClient {
const { password, ...client } = this;
return client;
}
However, score
is something that we want to return, so we change our UserClient
type to:
type UserClient = Omit<User, 'password' | 'score'> | { score: number };
and our toClient()
method now becomes:
toClient(): UserClient {
const { password, ...client } = this;
return {
score: this.score,
...client
}
}
This, however, gives the error 'score' is specified more than once, so this usage will be overwritten
, even though when we destructure an object, it doesn't give us the getters - it seems like the inferred type from this line:
const { password, ...client } = this;
is wrong (specifically, it's Omit<this, 'password'>
for client
). In order to fix it, I need to change that line to
const { password, score, ...client } = this;
This doesn't really have any effect on the underlying JavaScript code, so it's a minor bug (I think)
🔎 Search Terms
rest
destructuring
🕗 Version & Regression Information
I'm currently on 4.4.3
though running in TypeScript Playground, 3.9.7
is when it first seems to show up.
In that version, the inferred type is Pick<this, Exclude<keyof this, "password">>
In 3.8.3 the inferred type is the same, though the error isn't present, so there must have been a change to the underlying Pick
code (perhaps to include getters?)
- This changed between versions 3.8.3 and 3.9.7
⏯ Playground Link
💻 Code
class User {
constructor(
public uid: number,
public password: string // sensitive info
) { }
get score(): number {
return 10; // example code - imagine having to fetch something a little more complex
}
toClient(): UserClient {
const { password, ...client } = this;
return {
score: this.score, // ERROR: 'score' is specified more than once, so this usage will be overwritten
...client
}
}
}
type UserClient = Omit<User, 'password' | 'score'> | { score: number };
🙁 Actual behavior
The inferred type on client
seems to include getters
🙂 Expected behavior
The inferred type on client
to only include basic properties as it's created through destructuring