簡體   English   中英

是否可以在 TypeScript 注釋中組合多種類型的成員?

[英]Is it possible to combine members of multiple types in a TypeScript annotation?

似乎我想做的事情是不可能的,但我真的希望它是。

本質上,我有兩個接口,我想將單個函數參數注釋為它們的組合。

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

然后,在函數中,我想做這樣的事情:

function(data: ClientRequest&Coords) { ... }

這樣我的“數據”對象就可以包含這兩種類型的所有成員。

我在“組合類型的成員”下的規范預覽中看到了一些引用,但似乎這還沒有實現。

如果不可能,我的解決方案可能如下所示:

interface ClientRequest<T> {
    userId:     number
    sessionKey: string
    data?:       T
}

function(data: ClientRequest<Coords>) { ... }

這在這種情況下會起作用,盡管它不像我想要的那樣動態。 我真的希望能夠在注釋本身中組合多種(2+)類型:

function(data: TypeA&TypeB&TypeC) { ... }

我猜想傳統的解決方案是定義一個擴展這些類型的類型,盡管這似乎不太靈活。 如果我想添加一個類型,我必須要么

  • (a) 回到聲明並重寫它,或
  • (b) 創建一個全新的界面。 不確定我是否同意額外的開銷。

有沒有 TypeScript 專家願意為我指明正確的方向?

您的問題的具體答案是:不,沒有一個內聯注釋來表示組合或擴展類型。

您嘗試解決的問題的最佳實踐是創建第三種類型來擴展其他兩種類型。

interface IClientRequestAndCoords extends IClientRequest, ICoords {} 

function(data: IClientRequestAndCoords) 

更新2018-10-30

TypeScript 現在有類型交集。 所以你現在可以簡單地做:

interface ClientRequest {
  userId:     number
  sessionKey: string
}

interface Coords {
  lat:  number
  long: number
}

function log(data: ClientRequest & Coords) { 
  console.log(
    data.userId,
    data.sessionKey,
    data.lat,
    data.long
  );
}

如果你使用ES6 Object.assign是很有可能的。 假設您有這些類型的現有對象。

首先讓我們定義類型

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

現在兩者的結合:

type Combined = ClientRequest & Coords;

假設您有兩個想要傳遞給函數的現有對象:

const foo: ClientRequest = {
    userId: 10,
    sessionKey: "gjk23h872ty3h82g2ghfp928ge"
}

const bar: Coords = {
    lat: -23,
    long: 52
}

你可以像這樣組合它們:

const myData: Combined = Object.assign({}, foo, bar);

或者像這樣創建一個新的:

const myData: Combined = {
    userId: 10,
    sessionKey: "gjk23h872ty3h82g2ghfp928ge",
    lat: -23,
    long: 52,
}

以前的方法

不是類型安全的。

<Type> {...}語法將對象轉換為尖括號 ( Type ) 中指定的類型,這繞過了 Typescript 的檢查器。 請參閱類型斷言

const myData = Object.assign({},
    <ClientRequest> {
        userId: 10,
        sessionKey: "gjk23h872ty3h82g2ghfp928ge"
    },
    <Coords> {
        lat: -23,
        long: 52
    }
);

最后,調用函數:

function myFunc(data: Combined) { ... }
myFunc(myData);

有關完成此操作的更多方法,請參見其他問題:

如何動態合並兩個 JavaScript 對象的屬性?

接口答案是組合這兩種結構的一種相當優雅的方法,但您提到您想知道是否可以將類型組合為注釋的一部分。

關於接口的說明

我已經提供了與您的問題相關的一些功能的一些描述,但首先我要說的是,如果您因為認為必須創建一個ICoords界面而被推遲使用界面解決方案(因為在您的問題中它看起來更像一個類) - 休息一下 - 因為接口也可以擴展一個類:

// Interface extending an interface and a class
interface IClientRequestAndCoords extends IClientRequest, Coords {} 

只要屬性具有相同的名稱和類型,該接口甚至會合並屬性。 (例如,如果他們都聲明了一個屬性x: string

以下是您提到的其他注釋功能的注釋。

聯合類型

你可能讀過的規范是聯合類型,它看起來像這樣:

var x: IClientRequest | Coords;

但這只能確保x是其中之一,而不是兩者的組合。 據我所知,您的合並類型IClientRequest & Coords的語法不在路線圖上。

function go(data: IClientRequest | Coords) {
    var a = data[0]; // IClientRequest
    var b = data[1]; // Coords
}

// Allowed (even though it doesn't supply Coords data
go(myClientRequest);

// Allowed (even though it doesn't supply IClientRequest data
go (myCoords);

這也不是當前版本的一部分,但稍后會發布。

元組類型

您可能已經看到的規范的另一個可能部分是元組類型:

var x: [IClientRequest, Coords];

但這會將數據的形狀從結構更改為數組,其中元素0IClientRequest元素1Coords

function go(data: [IClientRequest, Coords]) {
    var a = data[0]; // ClientRequest
    var b = data[1]; // Coords
}

go([myClientRequest, myCoords]);

Uber-注解

最后,如果你真的不想創建一個合並的界面,你可以使用一個 uber-annotation:

function go(data: { userId:number; sessionKey: string; x: number; y: number; } ) {

}

現在,如果類型 P1 和 P2 擴展對象,您可以使用條件類型執行類似的操作:

type P1UnionP2 = { [k in (keyof P1 | keyof P2)]: k extends keyof P1 ? P1[k] : k extends keyof P2 ? P2[k] : never }

最好的方法是,如果這適用於您的情況,則:

interface P1UnionP2 extends P1, P2 { }

我在“組合類型的成員”下的規范預覽中看到了一些引用,但似乎這還沒有實現。

我認為您會對intersection類型(而不是union )更感興趣。 不同之處在於傳入的對象必須支持所有屬性,而不是.

Github 問題: https ://github.com/Microsoft/TypeScript/issues/1256#issuecomment-64533287

這是基於此答案的可重用實用程序類型,用於組合Record類型的聯合

type UnionToType<U extends Record<string, unknown>> = { [K in (U extends unknown ? keyof U : never)]: U extends unknown ? K extends keyof U ? U[K] : never : never}

type A = {
    a: string
}

type B = {
    b: number
}

type C = {
    c: boolean
}

type D = {
    c: A
}

type Combined = UnionToType<A | B | C | D>

/*
type Combined = {
    a: string;
    b: number;
    c: boolean | A;
}
*/

const combined1: Combined = {
    a: 'test',
    b: 2,
    c: {
        a: ''
    }
}

const combined2: Combined = {
    a: 'test',
    b: 2,
    c: false
}

游樂場示例

我只需要這樣做,以下解決方案對我有用:

type MyFunction = () => void

interface MyFunctionWithProps extends MyFunction {
  prop1: string,
  prop2: number
}

// compiles fine
const MyMashup: MyFunctionWithProps = Object.assign(
  () => {},
  {
    prop1: 'hello',
    prop2: 1234
  }
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM