有没有办法改变*.d.ts
打字稿中定义的接口属性的类型?
例如:中的接口x.d.ts
定义为
interface A {
property: number;
}
我想在我写的打字稿文件中更改它
interface A {
property: Object;
}
甚至这将工作
interface B extends A {
property: Object;
}
这种方法行得通吗?当我在系统上尝试时,它不起作用。只想确认是否有可能?
Answers:
您无法更改现有属性的类型。
您可以添加一个属性:
interface A {
newProperty: any;
}
但是更改现有的类型:
interface A {
property: any;
}
导致错误:
后续变量声明必须具有相同的类型。变量“属性”的类型必须为“数字”,但此处的类型为“任何”
您当然可以拥有自己的接口,以扩展现有接口。在这种情况下,您可以将类型仅覆盖为兼容类型,例如:
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
顺便说一句,您可能应该避免将其Object
用作类型,而应使用type any
。
在文档中,该any
类型指出:
any类型是使用现有JavaScript的强大方法,可让您在编译期间逐渐选择加入和选择退出类型检查。您可能希望Object像其他语言一样扮演相似的角色。但是Object类型的变量仅允许您为它们分配任何值-您不能在它们上调用任意方法,即使是实际存在的方法:
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'.
我使用一种方法,该方法首先过滤字段,然后将它们组合。
参考从类型中排除属性
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
用于界面:
interface A {
x: string
}
interface B extends Omit<A, 'x'> {
x: number
}
extend
工作在默认情况下,但很可惜,这个小Omit
补丁一切🙌
type ModifiedType = Modify<OriginalType, { a: number; b: number; }> interface ModifiedInterface extends Modify<OriginalType, { a: number; b: number; }> {}
受ZSkycat extends Omit
解决方案的启发,我想到了这一点:
type Modify<T, R> = Omit<T, keyof R> & R; // before typescript@3.5 type Modify<T, R> = Pick<T, Exclude<keyof T, keyof R>> & R
例:
interface OriginalInterface {
a: string;
b: boolean;
c: number;
}
type ModifiedType = Modify<OriginalInterface , {
a: number;
b: number;
}>
// ModifiedType = { a: number; b: number; c: number; }
逐步进行:
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; }
稍微扩展@zSkycat的答案,您可以创建一个泛型,该泛型接受两个对象类型,并返回合并后的类型与第二个对象的成员,并覆盖第一个成员的成员。
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;
有趣的是,我花了一整天的时间研究解决同一案件的可能性。我发现不可能这样做:
// a.ts - module
export interface A {
x: string | any;
}
// b.ts - module
import {A} from './a';
type SomeOtherType = {
coolStuff: number
}
interface B extends A {
x: SomeOtherType;
}
原因模块可能不知道您的应用程序中所有可用的类型。而且从任何地方移植所有内容并执行这样的代码非常无聊。
export interface A {
x: A | B | C | D ... Million Types Later
}
您稍后必须定义类型,以使自动完成功能正常运行。
因此,您可以作弊:
// a.ts - module
export interface A {
x: string;
}
默认情况下保留某种类型,该类型允许在不需要覆盖时自动完成工作。
然后
// b.ts - module
import {A} from './a';
type SomeOtherType = {
coolStuff: number
}
// @ts-ignore
interface B extends A {
x: SomeOtherType;
}
在这里使用@ts-ignore
标志禁用愚蠢的异常,告诉我们我们做错了什么。有趣的是,一切都按预期进行。
就我而言,我正在减小type的作用域视野x
,它使我的代码更加严格。例如,您有100个属性的列表,并将其减少到10个,以避免出现愚蠢的情况
为了缩小属性的类型,简单的方法很extend
完美,就像Nitzan的回答:
interface A {
x: string | number;
}
interface B extends A {
x: number;
}
要扩展或总体覆盖类型,可以执行Zskycat的解决方案:
interface A {
x: string
}
export type B = Omit<A, 'x'> & { x: number };
但是,如果您的接口A
扩展了通用接口,则使用时,您将丢失A
剩余属性的自定义类型Omit
。
例如
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!
原因是,Omit
内部仅遍历Exclude<keyof A, 'x'>
密钥,这string | number
在我们的情况下是通用的。因此,B
将成为{x: number; }
并接受类型为的任何其他属性number | string | boolean
。
为了解决这个问题,我想出了一种不同的OverrideProps
实用程序类型,如下所示:
type OverrideProps<M, N> = { [P in keyof M]: P extends keyof N ? N[P] : M[P] };
例:
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!
如果其他人需要通用实用程序类型来执行此操作,则可以提出以下解决方案:
/**
* Returns object T, but with T[K] overridden to type U.
* @example
* type MyObject = { a: number, b: string }
* OverrideProperty<MyObject, "a", string> // returns { a: string, b: string }
*/
export type OverrideProperty<T, K extends keyof T, U> = Omit<T, K> & { [P in keyof Pick<T, K>]: U };
我需要它,因为在我的情况下,覆盖的关键是通用名称本身。
如果您还没有Omit
准备好,请参见从type中排除属性。