覆盖Typescript d.ts文件中定义的覆盖接口属性类型

Abd*_*l23 60 javascript typescript typescript-typings

有没有办法更改*.d.tsintype中定义的接口属性的类型?

例如:接口in x.d.ts定义为

interface A {
  property: number;
}
Run Code Online (Sandbox Code Playgroud)

我想在我写的typescript文件中更改它

interface A {
  property: Object;
}
Run Code Online (Sandbox Code Playgroud)

甚至这会起作用

interface B extends A {
  property: Object;
}
Run Code Online (Sandbox Code Playgroud)

这种方法会起作用吗?当我尝试使用我的系统时,它无法正常工作.只是想确认它是否可能?

小智 65

我使用的方法首先过滤字段,然后将它们组合起来.

reference 从类型中排除属性

interface A {
    x: string
}

export type B = Omit<A, 'x'> & { x: number };
Run Code Online (Sandbox Code Playgroud)

用于界面:

interface A {
    x: string
}

interface B extends Omit<A, 'x'> {
  x: number
}
Run Code Online (Sandbox Code Playgroud)

  • 很高兴知道这一点。但问题是它仍然没有修改现有的。 (8认同)
  • // 省略单个属性: type OmitA = Omit&lt;Test, "a"&gt;; // 相当于: {b: number, c: boolean} // 或者,省略多个属性: type OmitAB = Omit&lt;Test, "a"|"b"&gt;; // 等价于:{c: boolean} (4认同)
  • 这正是我想要的。这就是我希望打字稿`extend`在默认情况下可以正常工作的方式,但是,这个`Omit`可以解决所有问题 (2认同)
  • 扩展接口正是我所寻找的,谢谢! (2认同)
  • 注意:您需要 Typescript 3.5.3 以上才能使用它。 (2认同)

Qwe*_*rty 37

type ModifiedType = Modify<OriginalType, {
  a: number;
  b: number;
}>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

例:

interface OriginalType {
  a: string;
  b: boolean;
  c: number;
}

type ModifiedType  = Modify<OriginalType , {
  a: number;
  b: number;
}>

// ModifiedType = { a: number; b: number; c: number; }
Run Code Online (Sandbox Code Playgroud)

逐步进行:

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; }
Run Code Online (Sandbox Code Playgroud)

TypeScript实用程序类型

  • 这是一个很好的解决方案。 (14认同)
  • 这应该成为 TS 的一个功能 (3认同)
  • 这里是菜鸟,但您在示例中从接口更改为类型,不是吗?还是没有区别? (2认同)
  • @Dominic 好点,我已经更新了答案。两个同名的接口可以合并。https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces (2认同)
  • @Donnovan这是一个自定义类型,再次查看答案找到-&gt;`类型Modify&lt;T, R&gt; = Omit&lt;T, keyof R&gt; &amp; R;` (2认同)

Nit*_*mer 33

您无法更改现有属性的类型.

您可以添加属性:

interface A {
    newProperty: any;
}
Run Code Online (Sandbox Code Playgroud)

但改变一种现有的类型:

interface A {
    property: any;
}
Run Code Online (Sandbox Code Playgroud)

导致错误:

后续变量声明必须具有相同的类型.变量'property'必须是'number'类型,但这里有'any'类型

您当然可以拥有自己的界面,扩展现有界面.在这种情况下,您只能将类型覆盖为兼容类型,例如:

interface A {
    x: string | number;
}

interface B extends A {
    x: number;
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你可能应该避免使用Object类型,而是使用类型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'.
Run Code Online (Sandbox Code Playgroud)

  • @wvdz 并不是说​​我很关心反对票,但你在说什么?哪里有人提到过java?在页面中搜索“java”只有一个结果,并且在您的评论中。 (4认同)
  • 您确定可以通过继承覆盖类型吗?这对我的机器不起作用。我尝试覆盖角度资源的``保存''方法。 (3认同)
  • 哎呀,对不起,我的错。说实话,就算是你这么说,我也只是脾气有点暴躁而已。不幸的是,无法再删除反对票了。 (2认同)
  • RE *“您可能应该避免使用`Object`作为类型,而是使用类型`any`”* - 我**永远不会**推荐某人使用`any`。几乎没有理由使用它。人们使用它的最常见原因是缺乏对如何输入内容的理解。仅当您“需要”“动态”类型时才使用此选项。否则,使用“未知”或泛型类型。 (2认同)

rya*_*ffy 25

稍微扩展@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;
Run Code Online (Sandbox Code Playgroud)

  • 非常酷 :-) 我之前已经使用 Omit 使用一两个属性完成了此操作,但这更酷 :-) 我经常想要“扩展”服务器实体类型并更改客户端上必需或可选的一些内容。 (2认同)

JmJ*_*JmJ 24

Omit 扩展接口时的属性:

interface A {
  a: number;
  b: number;
}

interface B extends Omit<A, 'a'> {
  a: boolean;
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ian 24

覆盖接口的两个多个属性的解决方案:

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
}
Run Code Online (Sandbox Code Playgroud)

来自TypeScript 文档


Mas*_*iri 11

对于像我这样懒惰的人的简短回答:

type Overrided = Omit<YourInterface, 'overrideField'> & { overrideField: <type> }; 
Run Code Online (Sandbox Code Playgroud)

  • 这也是 [ZSkycat] 接受的解决方案的 1:1 副本(/sf/ask/2889964801/ 51507473#51507473)。 (2认同)

Qwe*_*rty 9

深度修改v4

\n

我目前正在我的要点中构建一个更强大的解决方案,可以更好地处理数组并允许删除键或修改其?可选性

\n
interface Original {\n  x: {\n    a: string\n    b: string\n  }\n}\n\ninterface Overrides {\n  x: {\n    a: never // <- this key will be deleted\n    b?: string // <- this will become optional\n  }\n}\n\n/* result = {\n  x: {\n    b?: string\n  }\n} */ \n
Run Code Online (Sandbox Code Playgroud)\n

深度修改v3

\n

*注意,版本 2 在此答案的历史记录中。

\n
interface Original {\n  a: {\n    a: string\n    b: { a: string }\n    c: string\n    d: string         // <- keep this one \n  }\n}\n\ninterface Overrides {\n  a: {\n    a: { a: number }  // <- overwrite string with object\n    b: number         // <- overwrite object with number\n    c: number         // <- overwrite string with number\n    e: number         // <- new property\n  }\n}\n\ntype ModifiedType = ModifyDeep<Original, Overrides>\ninterface ModifiedInterface extends ModifyDeep<Original, Overrides> {}\n
Run Code Online (Sandbox Code Playgroud)\n
结果
\n
const example: ModifiedType = {\n  a: {\n    a: { a: number },\n    b: number,\n    c: number,\n    d: string,\n    e: number,\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
代码
\n
type ModifyDeep<A, B extends DeepPartialAny<A>> = {\n  [K in keyof A | keyof B]:            // For all keys in A and B:\n    K extends keyof A                  // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n      ? K extends keyof B              // \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80 key K exists in both A and B\n        ? A[K] extends AnyObject       //    \xe2\x94\x82  \xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n          ? B[K] extends AnyObject     //    \xe2\x94\x82  \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80 both A and B are objects\n            ? B[K] extends AnyFunction //    \xe2\x94\x82     \xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 Avoid deeply modifying functions which results in {}\n              ? B[K]                   //    \xe2\x94\x82     \xe2\x94\x82  \xe2\x94\x82\n              : ModifyDeep<A[K], B[K]> //    \xe2\x94\x82     \xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80 We need to go deeper (recursively)\n            : B[K]                     //    \xe2\x94\x82     \xe2\x94\x9c\xe2\x94\x80 B is a primitive  use B as the final type (new type)\n          : B[K]                       //    \xe2\x94\x82     \xe2\x94\x94\xe2\x94\x80 A is a primitive  use B as the final type (new type)  \n        : A[K]                         //    \xe2\x94\x9c\xe2\x94\x80 key only exists in A  use A as the final type (original type)   \n      : B[K]                           //    \xe2\x94\x94\xe2\x94\x80 key only exists in B  use B as the final type (new type)\n}\n\ntype AnyObject = Record<string, any>\ntype AnyFunction = (...args: any[]) => any\n\n// This type is here only for some intellisense for the overrides object\ntype DeepPartialAny<T> = {\n  /** Makes each property optional and turns each leaf property into any, allowing for type overrides by narrowing any. */\n  [P in keyof T]?: T[P] extends AnyObject ? DeepPartialAny<T[P]> : any\n}\n
Run Code Online (Sandbox Code Playgroud)\n

*注意, typeDeepPartialAny只是用于类型提示,但它并不完美。从技术上讲,\xc2\xa0type 的逻辑ModifyDeep允许{a: string}用对象替换叶节点{a: {b: ... }},反之亦然,但是DeepPartialAny当用平面原语覆盖 an 时会出现如下object错误:

\n
Type \'number\' has no properties in common with type \'DeepPartialAny<{ a: string; }>\'\n
Run Code Online (Sandbox Code Playgroud)\n

但是,您可以安全地忽略该错误(使用/// @ts-ignoreextends DeepPartialAny完全删除约束。无论如何,结果类型都会正确计算。

\n

例子

\n

TypeScript 游乐场

\n
interface Original {\n  x: {\n    a: string\n    b: string\n  }\n}\n\ninterface Overrides {\n  x: {\n    a: never // <- this key will be deleted\n    b?: string // <- this will become optional\n  }\n}\n\n/* result = {\n  x: {\n    b?: string\n  }\n} */ \n
Run Code Online (Sandbox Code Playgroud)\n


Aid*_*din 6

为了缩小属性的类型,简单的extend作品很完美,如Nitzan 的回答

interface A {
    x: string | number;
}

interface B extends A {
    x: number;
}
Run Code Online (Sandbox Code Playgroud)

对于扩大或一般覆盖类型,您可以执行Zskycat 的解决方案

interface A {
    x: string
}

export type B = Omit<A, 'x'> & { x: number };
Run Code Online (Sandbox Code Playgroud)

但是,如果您的接口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! 
Run Code Online (Sandbox Code Playgroud)

原因是,在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] };
Run Code Online (Sandbox Code Playgroud)

例子:

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!
Run Code Online (Sandbox Code Playgroud)


yon*_*ang 6

日期:2021 年 3 月 19 日。我认为最新的打字稿(4.1.2)版本支持文件interface中的覆盖d.ts

// in test.d.ts

interface A {
  a: string
}

export interface B extends A {
  a: number
}

// in any ts file
import { B } from 'test.d.ts'

// this will work
const test: B = { a: 3 }

// this will not work
const test1: B = { a: "3" }

Run Code Online (Sandbox Code Playgroud)

  • 我来自未来。它不起作用“错误地扩展了接口” (4认同)

mik*_*ism 6

覆盖为别名类型

您可以使用此类型别名:

type Override<T, K extends { [P in keyof T]: any } | string> =
  K extends string
    ? Omit<T, K>
    : Omit<T, keyof K> & K;
Run Code Online (Sandbox Code Playgroud)

并使用类似以下语法:

全球接口

interface IFirst {
    username: string;
}
Run Code Online (Sandbox Code Playgroud)

接口override名称

interface ISecond extends Override<IFirst, 'username'> {
    username: number;
}
Run Code Online (Sandbox Code Playgroud)

类型别名override

type IThird = Override<IFirst, { username: boolean }>;
Run Code Online (Sandbox Code Playgroud)

编辑 :

我尝试通过将问题作为提案发送到Typescript Repo来将此别名类型添加为 Typescript 中的内置类型


ita*_*ded 5

我创建了这种允许我轻松覆盖嵌套接口的类型:

type ModifyDeep<A extends AnyObject, B extends DeepPartialAny<A>> = {
  [K in keyof A]: B[K] extends never
    ? A[K]
    : B[K] extends AnyObject
      ? ModifyDeep<A[K], B[K]>
      : B[K]
} & (A extends AnyObject ? Omit<B, keyof A> : A)

/** Makes each property optional and turns each leaf property into any, allowing for type overrides by narrowing any. */
type DeepPartialAny<T> = {
  [P in keyof T]?: T[P] extends AnyObject ? DeepPartialAny<T[P]> : any
}

type AnyObject = Record<string, any>
Run Code Online (Sandbox Code Playgroud)

然后你可以这样使用它:

interface Original {
  a: {
    b: string
    d: {
      e: string // <- will be changed
    }
  }
  f: number
}

interface Overrides {
  a: {
    d: {
      e: number
      f: number // <- new key
    }
  }
  b: {         // <- new key
    c: number
  }
}

type ModifiedType = ModifyDeep<Original, Overrides>
interface ModifiedInterface extends ModifyDeep<Original, Overrides> {}
Run Code Online (Sandbox Code Playgroud)
// ModifiedType =
{
  a: {
    b: string
    d: {
      e: number
      f: number
    }
  }
  b: {
    c: number
  }
  f: number
}
Run Code Online (Sandbox Code Playgroud)


ktr*_*yak 5

尝试这个:

type Override<T extends object, K extends { [P in keyof T]?: any }> = Omit<T, keyof K> & K;
Run Code Online (Sandbox Code Playgroud)

用法:

type TransformedArticle = Override<Article, { id: string }>;
Run Code Online (Sandbox Code Playgroud)


小智 5

有时,上述解决方案没有帮助。如果出现以下情况,就会发生这种情况。

interface A {
    [k: string]: string;
}

interface B extends A {}

type C = Omit<B, 'x'> & { x: number }
Run Code Online (Sandbox Code Playgroud)

C中的x始终为字符串类型。如果您想覆盖例如process.env类型,则这是实际的

为了解决这个问题。您需要通过以下方式重写接口A,以更严格的方式删除键


interface C {
    x: number;
}

type ExcludeKeys<Type, Keys> = {
    [Property in keyof Type as Exclude<Property, Keys>]: Type[Property];
};

type AA = ExcludeKeys<B, keyof C> & C;
Run Code Online (Sandbox Code Playgroud)