Typecript arayüzündeki tüm özellikleri isteğe bağlı yapın


96

Uygulamamda bir arayüz var:

interface Asset {
  id: string;
  internal_id: string;
  usage: number;
}

bu bir gönderi arayüzünün parçasıdır:

interface Post {
  asset: Asset;
}

Ayrıca, varlık nesnesinin yalnızca kısmen oluşturulabileceği bir taslak sonrası için bir arayüzüm var

interface PostDraft {
  asset: Asset;
}

Bir PostDraftnesnenin, var olan özelliklerdeki türleri kontrol etmeye devam ederken kısmi bir varlık nesnesine sahip olmasına izin vermek istiyorum (bu yüzden onu sadece takas etmek istemiyorum any).

Temel olarak aşağıdakileri oluşturmanın bir yolunu istiyorum:

interface AssetDraft {
  id?: string;
  internal_id?: string;
  usage?: number;
}

Assetarayüzü tamamen yeniden tanımlamadan . Bunu yapmanın bir yolu var mı? Değilse, türlerimi bu durumda düzenlemenin akıllıca yolu ne olurdu?


Bugün bu ikinci arayüzü manuel olarak yapmanız gerekiyor, ancak bu yakın gelecekte değişebilir: ilgileniyorsanız ts repo'sundaki kısmi tür sorununa bakın.
Alex Guerra

Yanıtlar:


208

TypeScript <2.1'de isteğe bağlı özelliklerle ek bir arayüz oluşturmadan bu mümkün değildir; ancak bu, TypeScript 2.1+ içinde eşlenmiş türler kullanılarak mümkündür.

Bunu yapmak için, Partial<T>TypeScript'in varsayılan olarak sağladığı türü kullanın .

interface PostDraft {
    asset: Partial<Asset>;
}

Şimdi üzerindeki tüm özellikler assetisteğe bağlıdır ve aşağıdakileri yapmanıza izin verir:

const postDraft: PostDraft = {
    asset: {
        id: "some-id"
    }
};

hakkında Partial<T>

Partial<T>, sağlanan türdeki her özelliği isteğe bağlı kılan ( belirteci kullanarak ) eşlenmiş bir tür olarak tanımlanır? .

type Partial<T> = {
    [P in keyof T]?: T[P];
};

Eşlenmiş türler hakkında daha fazla bilgiyi burada ve el kitabında okuyun .


@david diğer tarafa gitmek mümkün mü? Önceden kısmi olan alanları zorunlu olarak işaretlemek için? Ayrıca alan bazında yapmak da mümkün mü?
Tony

1
@Tony evet, TS 2.8'deki koşullu tipler ile mümkün olacaktır (bakınız Required<T>).
David Sherret

2
Aman tanrım, bu çok temiz bir çözüm. Keşke bunu biraz daha erken bilseydim
CiriousJoker

3
Microsoft'tan TS'ye giren düşünceye hayran kalmaya devam etti ... Aynı amacın web tarayıcısı geliştirmelerine (-_-) de
girmesini dilerdim

4

Arayüzdeki özellikler isteğe bağlı değildir, aynı arayüzü bir kez isteğe bağlı ve bir kez olması gerektiği gibi kullanamazsınız.

Yapabileceğiniz şey, için isteğe bağlı özelliklere sahip bir arabirime AssetDraftve ardından aşağıdakiler için zorunlu özelliklere sahip bir sınıfa sahip olmaktır Asset:

interface AssetDraft {
    id?: string;
    internal_id?: string;
    usage?: number;
}

class Asset {
    static DEFAULT_ID = "id";
    static DEFAULT_INTERNAL_ID = "internalid";
    static DEFAULT_USAGE = 0;

    id: string;
    internal_id: string;
    usage: number;

    constructor(draft: AssetDraft) {
        this.id = draft.id || Asset.DEFAULT_ID;
        this.internal_id = draft.internal_id || Asset.DEFAULT_INTERNAL_ID;
        this.usage = draft.usage || Asset.DEFAULT_USAGE;
    }
}

Buradaki varsayılan değerler statik üyelerdir, ancak bunları başka yollarla alabilir veya eksik olmaları durumunda bir hata atabilirsiniz.

Sunucudan alınan json'larla (veya benzer bir şeyle) çalışırken bu yolu çok rahat buluyorum, arabirimler json verilerini temsil ediyor ve sınıflar, başlangıç ​​değerleri olarak json'lar kullanılarak oluşturulan gerçek modellerdir.


Evet yapabilirsiniz .. David Sherret cevabında belirtildiği gibi ... arayüzünüzü Kısmi <T> ..T arayüzünüz olarak geçirmek için jenerik tip değişkeni kullanmanız gerekir.
greatKing

@greaterKing artık mümkün ve kolay
Nitzan Tomer

1

Açık bir AssetDraftarayüze sahip olmak istersem , extendsve aşağıdakilerin bir kombinasyonunu kullanırdım Partial:

interface Asset {
  id: string;
  internal_id: string;
  usage: number;
}

interface AssetDraft extends Partial<Asset> {}

0

David Sherret'e ek olarak Partial<T>, konunun daha iyi anlaşılması için yazı olmadan doğrudan nasıl uygulanabileceği benim tarafımdan sadece birkaç satıra cevap veriyor .

interface IAsset {
  id: string;
  internal_id: string;
  usage: number;
}

interface IPost {
  asset: IAsset;
}

interface IPostDraft {
  asset: { [K in keyof IAsset]?: IAsset[K] };
}

const postDraft: IPostDraft = {
  asset: {
    usage: 123
  }
};

-1

Boş bir nesneye kuvvet atmaya ne dersiniz?

const draft = <PostDraft>{}
draft.id = 123
draft.internal_id = 456
draft.usage = 789

Buna gerçekten ihtiyacınız varsa, hem isteğe bağlı hem de yazılan özellikleri yapan bir şablondan her zaman bir d.ts arabirimi oluşturabilirsiniz.

Nitzan'ın belirttiği gibi, Typescript arayüz özelliklerinden herhangi biri isteğe bağlıdır veya değildir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.