gitbeaker
gitbeaker copied to clipboard
Types is incorrect after omitting keys
Description
After omitting some fields from existing Schema types, the types of remained fields become unknown
.
Steps to reproduce
const api = new Gitlab({ token: 'token' });
const branch = await api.Branches.show('projectId', 'master');
const commitDiff = await api.Commits.diff('projectId', branch.commit.id);
// TS2345: Argument of type 'unknown' is not assignable to parameter of type 'string'.
Expected behaviour
The type of branch.commit.id
should be string
.
Actual behaviour
The type of branch.commit.id
is unknown
.
Possible fixes
All Schema types extend from Record<string, unknown>
. For example:
interface Foo extends Record<string, unknown> {
x: string;
y: number;
z: boolean;
}
type K0 = keyof Foo; // string | number
type K1 = Exclude<K0, 'x'>; // string | number
type T = Omit<Foo, 'x'>; // { [x: string]: unknown, [x: number]: unknown }
While the other is not extended from Record
type:
interface Bar {
x: string;
y: number;
z: boolean;
}
type K0 = keyof Bar; // 'x' | 'y' | 'z'
type K1 = Exclude<K0, 'x'>; // 'y' | 'z'
type T = Omit<Bar, 'x'>; // { y: number, z: boolean }
Because Omit
is implemented by Exclude
, so the excluded keys is incorrect if the object type extends from Record
type.
https://github.com/microsoft/TypeScript/issues/36981 Looks like a larger problem
Seems that this issue has been rescheduled. The related PR resolve the problem by writing Omit
with remapping (microsoft/TypeScript#42524). However, key remapping via as
was introduced since TypeScript 4.1, users who use an old version of TypeScript will get syntax error.
@jdalrymple Sorry for the ping, but probably it won't be fixed any time soon.
As a workaround, I suggest using a utility type instead of Omit
. Exept provided by type-fest works fine it seems.
I prepared an example with BranchSchema
:
export interface BranchSchema extends Record<string, unknown> {
...
commit: Omit<CommitSchema, 'web_url' | 'created_at'>;
}
Direct usage of CommitSchema
works just fine:
let date: Date | undefined;
let title: string;
const commit: CommitSchema = {} as any;
title = commit.title; // no errors
date = commit.created_at; // no errors
However, for BranchSchema
it shows an error:
const branch: BranchSchema = {} as any;
title = branch.commit.title; // Type 'unknown' is not assignable to type 'string'.(2322)
date = branch.commit.created_at; // Type 'unknown' is not assignable to type 'Date | undefined'.(2322)
In another example I replaced Omit
with Except
and now only expected error is shown:
export interface BranchSchema extends Record<string, unknown> {
...
commit: Except<CommitSchema, 'web_url' | 'created_at'>;
}
const branch: BranchSchema = {} as any;
title = branch.commit.title; // no errors
date = branch.commit.created_at; // Type 'unknown' is not assignable to type 'Date | undefined'.(2322)
Good find! I keep this in mind to make the tweak when i have a moment!
@jdalrymple Is it fixed? I still see Omit
usages in the types.
Now that i review this, it looks like i didn't fully solve this previously. I will now though! Should have it back up in an hour or so
I see that you are in Montreal, I should definitely buy you a beer someday
Gonna try this type: https://github.com/microsoft/TypeScript/issues/54451(MappedOmit), looks alot stricter than Omit, tell me if you run into any problems once i deploy!
:rocket: Issue was released in 38.12.0
:rocket: