admin管理员组文章数量:1125785
Is there a way to change the type of interface property defined in a *.d.ts
in typescript?
for example:
An interface in x.d.ts
is defined as
interface A {
property: number;
}
I want to change it in the typescript files that I write to
interface A {
property: Object;
}
or even this would work
interface B extends A {
property: Object;
}
Will this approach work? It didn't work when I tried on my system. Just want to confirm if it's even possible?
Is there a way to change the type of interface property defined in a *.d.ts
in typescript?
for example:
An interface in x.d.ts
is defined as
interface A {
property: number;
}
I want to change it in the typescript files that I write to
interface A {
property: Object;
}
or even this would work
interface B extends A {
property: Object;
}
Will this approach work? It didn't work when I tried on my system. Just want to confirm if it's even possible?
Share Improve this question edited Feb 14, 2019 at 11:14 Cœur 38.6k26 gold badges202 silver badges276 bronze badges asked Dec 22, 2016 at 14:18 Abdul23Abdul23 5,9852 gold badges17 silver badges23 bronze badges 023 Answers
Reset to default 1054I use a method that first filters the fields and then combines them.
reference Exclude property from type
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
for interface:
interface A {
x: string
}
interface B extends Omit<A, 'x'> {
x: number
}
type ModifiedType = Modify<OriginalType, {
a: number;
b: number;
}>
interface ModifiedInterface extends Modify<OriginalType, {
a: number;
b: number;
}> {}
Inspired by ZSkycat's extends Omit
solution, I came up with this:
type Modify<T, R> = Omit<T, keyof R> & R; // before [email protected] type Modify<T, R> = Pick<T, Exclude<keyof T, keyof R>> & R
Example:
interface OriginalInterface {
a: string;
b: boolean;
c: number;
}
type ModifiedType = Modify<OriginalInterface , {
a: number;
b: number;
}>
// ModifiedType = { a: number; b: number; c: number; }
Going step by step:
type R0 = Omit<OriginalType, 'a' | 'b'> // { c: number; }
type R1 = R0 & {a: number, b: number } // { a: number; b: number; c: number; }
type T0 = Exclude<'a' | 'b' | 'c' , 'a' | 'b'> // 'c'
type T1 = Pick<OriginalType, T0> // { c: number; }
type T2 = T1 & {a: number, b: number } // { a: number; b: number; c: number; }
TypeScript Utility Types
Deep Modification v3
interface Original {
a: {
a: string
b: { a: string }
c: string
d: string // <- keep this one
}
}
interface Overrides {
a: {
a: { a: number } // <- overwrite string with object
b: number // <- overwrite object with number
c: number // <- overwrite string with number
e: number // <- new property
}
}
type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
const example: ModifiedType = {
a: {
a: { a: number },
b: number,
c: number,
d: string,
e: number,
}
}
Find ModifyDeep
below.
The short answer for lazy people like me:
type Overrided = Omit<YourInterface, 'overrideField'> & { overrideField: <type> };
interface Overrided extends Omit<YourInterface, 'overrideField'> {
overrideField: <type>
}
You can't change the type of an existing property.
You can add a property:
interface A {
newProperty: any;
}
But changing a type of existing one:
interface A {
property: any;
}
Results in an error:
Subsequent variable declarations must have the same type. Variable 'property' must be of type 'number', but here has type 'any'
You can of course have your own interface which extends an existing one. In that case, you can override a type only to a compatible type, for example:
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
By the way, you probably should avoid using Object
as a type, instead use the type any
.
In the docs for the any
type it states:
The any type is a powerful way to work with existing JavaScript, allowing you to gradually opt-in and opt-out of type-checking during compilation. You might expect Object to play a similar role, as it does in other languages. But variables of type Object only allow you to assign any value to them - you can’t call arbitrary methods on them, even ones that actually exist:
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
Extending @zSkycat's answer a little, you can create a generic that accepts two object types and returns a merged type with the members of the second overriding the members of the first.
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
interface A {
name: string;
color?: string;
}
// redefine name to be string | number
type B = Merge<A, {
name: string | number;
favorite?: boolean;
}>;
let one: A = {
name: 'asdf',
color: 'blue'
};
// A can become B because the types are all compatible
let two: B = one;
let three: B = {
name: 1
};
three.name = 'Bee';
three.favorite = true;
three.color = 'green';
// B cannot become A because the type of name (string | number) isn't compatible
// with A even though the value is a string
// Error: Type {...} is not assignable to type A
let four: A = three;
Omit
the property when extending the interface:
interface A {
a: number;
b: number;
}
interface B extends Omit<A, 'a'> {
a: boolean;
}
Solution for overwriting two or more properties of an interface:
interface BaseInterface {
a: string;
b: string;
c: string;
}
interface ModifiedInterface extends Omit<BaseInterface, 'a' | 'b'> {
a?: string; // make it optional
b: boolean; // make it boolean
d: number; // add another property
}
From TypeScript documentation
I have created this type that allows me to easily override nested interfaces:
export type DeepPartialAny<T> = {
[P in keyof T]?: T[P] extends Obj ? DeepPartialAny<T[P]> : any;
};
export type Override<A extends Obj, AOverride extends DeepPartialAny<A>> = { [K in keyof A]:
AOverride[K] extends never
? A[K]
: AOverride[K] extends Obj
? Override<A[K], AOverride[K]>
: AOverride[K]
};
And then you can use it like that:
interface Foo {
Bar: {
Baz: string;
};
}
type Foo2 = Override<Foo, { Bar: { Baz: number } }>;
const bar: Foo2['Bar']['Baz'] = 1; // number;
For narrowing the type of the property, simple extend
works perfect, as in Nitzan's answer:
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
For widening, or generally overriding the type, you can do Zskycat's solution:
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
But, if your interface A
is extending a general interface, you will lose the custom types of A
's remaining properties when using Omit
.
e.g.
interface A extends Record<string | number, number | string | boolean> {
x: string;
y: boolean;
}
export type B = Omit<A, 'x'> & { x: number };
let b: B = { x: 2, y: "hi" }; // no error on b.y!
The reason is, Omit
internally only goes over Exclude<keyof A, 'x'>
keys which will be the general string | number
in our case. So, B
would become {x: number; }
and accepts any extra property with the type of number | string | boolean
.
To fix that, I came up with a different OverrideProps
utility type as following:
type OverrideProps<M, N> = { [P in keyof M]: P extends keyof N ? N[P] : M[P] };
Example:
type OverrideProps<M, N> = { [P in keyof M]: P extends keyof N ? N[P] : M[P] };
interface A extends Record<string | number, number | string | boolean> {
x: string;
y: boolean;
}
export type B = OverrideProps<A, { x: number }>;
let b: B = { x: 2, y: "hi" }; // error: b.y should be boolean!
Deep modification v4
I am currently building a more robust solution in my gist that better handles arrays and allows to remove a key or modify its ?
optionality.
interface Original {
x: {
a: string
b: string
}
}
interface Overrides {
x: {
a: never // <- this key will be deleted
b?: string // <- this will become optional
}
}
/* result = {
x: {
b?: string
}
} */
Deep modification v3
*note, version 2 is in the history of this answer.
interface Original {
a: {
a: string
b: { a: string }
c: string
d: string // <- keep this one
}
}
interface Overrides {
a: {
a: { a: number } // <- overwrite string with object
b: number // <- overwrite object with number
c: number // <- overwrite string with number
e: number // <- new property
}
}
type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
Result
const example: ModifiedType = {
a: {
a: { a: number },
b: number,
c: number,
d: string,
e: number,
}
}
The code
type ModifyDeep<A, B extends DeepPartialAny<A>> = {
[K in keyof A | keyof B]: // For all keys in A and B:
K extends keyof A // ───┐
? K extends keyof B // ───┼─ key K exists in both A and B
? A[K] extends AnyObject // │ ┴──┐
? B[K] extends AnyObject // │ ───┼─ both A and B are objects
? B[K] extends AnyFunction // │ │ ├─ Avoid deeply modifying functions which results in {}
? B[K] // │ │ │
: ModifyDeep<A[K], B[K]> // │ │ └─── We need to go deeper (recursively)
: B[K] // │ ├─ B is a primitive
本文标签:
javascriptOverriding interface property type defined in Typescript dts fileStack Overflow
版权声明:本文标题:javascript - Overriding interface property type defined in Typescript d.ts file - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:http://www.betaflare.com/web/1736674772a1947120.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论