TypeScript'te tip güvenli bir nesneyi aşamalı olarak nasıl oluşturulur
Bu tipik kalıp için zarif bir çözüm olduğundan eminim ama bir nesneyi tür güvenli bir şekilde kademeli olarak nasıl oluşturacağımı anlamakta zorlanıyorum. Temelde, sadece önceden tanımlanmış bir türle bir nesne oluşturmak istiyorum; önce boş bir nesne oluşturarak ve sonra gerekli özellikleri ekleyerek. (Bunu bir kerede oluşturmanın sorun yaratmayacağını anlıyorum ama benim kullanım durumum kademeli oluşturmayı gerektiriyor)
Aşağıdaki örnekler, denemekte olduğum seçenekleri ve her yaklaşımın sorunlarını göstermektedir:
type myType = {
foo: string,
bar: number,
};
// has errors
function createA(): myType {
const o = {};
o.foo = 'foo'; // Error: Property 'foo' does not exist on type '{}'
o.bar = 0; // Error: Property 'bar' does not exist on type '{}'
return o; // Error: Type '{}' is missing the following properties from type 'myType': foo, bar
}
// has errors
function createB(): myType {
const o: myType = {}; // Type '{}' is missing the following properties from type 'myType': foo, bar
o.foo = 'foo';
o.bar = 0;
return o;
}
// has errors
function createC(): myType {
const o = {};
o['foo'] = 'foo'; // Error: Element implicitly has an 'any' type because type '{}' has no index signature.
o['bar'] = 0; // Error: Element implicitly has an 'any' type because type '{}' has no index signature.
return o; // Error: Type '{}' is missing the following properties from type 'myType': foo, bar
}
// no errors but not type-save
function createD(): myType {
const o: any = {};
o.foo = 'foo';
return o; // No error but object does not contain the required 'bar' property
}
// no errors but not type-save
function createE(): myType {
const o: any = {};
o.foo = 'foo';
return o; // No error but object does not contain the required 'bar' property
}
// no errors but not type-save
function createF(): myType {
const o: myType = <any>{};
o.foo = 'foo';
return o; // No error but object does not contain the required 'bar' property
}
// no errors but not type-save
function createG(): myType {
const oFoo = {foo: 'foo'};
const oBar = {bar: 0};
return Object.assign(oFoo); // No error but object does not contain the required 'bar' property
}
// no errors and type-save but very convolute and expensive for a large number of properties
function createH(): myType {
const foo = 'foo';
const bar = 0;
return {foo, bar};
}
Cevap #1
İki seçeneğiniz var:
- Builder desenini kullan.
- Builder desenine basit bir alternatif kullanın:
Expandable.
Bu tür, ihtiyaç duyuldukça nesneler oluşturmaya olanak tanır.
interface Expandable {
extend<T>(properties: T): this & T;
}
Boş bir nesne ile başlarsınız ve uygun gördüğünüzde ona özellikler eklersiniz.
declare const base: Expandable;
const result: MyType =
base
.extend({ foo: 'hello '})
.extend({ bar: 42 });
Temeli genişletirken IntelliSense istiyorsanız, bunu Expandable'i jenerik yaparak yapabiliriz. Olası bir uygulama:
type Slice<T> = { [P in keyof T]: Pick<T, P> }[keyof T];
class Extendable<T> {
extend<U extends Slice<T>>(properties: U): this & U {
return Object.assign(this, properties);
}
}
function create(): MyType {
const base = new Extendable<MyType>();
return base
.extend({ foo: 'hello' })
.extend({ bar: 42 })
}
Cevap #2
MyType alanlarını isteğe bağlı yapabilirsiniz.
type MyType = {
foo?: string;
bar?: number;
};
Veya basitçe ek değişkenler kullanabilir ve sonunda beklenen türde bir nesne oluşturabilirsiniz.
type MyType = {
foo: string,
bar: number,
};
function create(): MyType {
const foo = 'foo';
const bar = 0;
return {
foo,
bar
}; // infers type
}
