Answer the question
In order to leave comments, you need to log in
How to instantiate a complex type?
Let's say there is such an interface ( in fact, it is of course much more complicated ):
interface Some {
value: string | string[];
}
const foo: Some = {
value: ['a', 'b'] // здесь всегда будет массив
};
foo.value.map(() => {}); // Property 'map' does not exist on type 'string | string[]'
function SomeType<T extends Some>(value: T): T {
return value
}
const bar = SomeType({
value: ['a', 'b'] // здесь всегда будет массив
});
bar.value.map(() => {}); // ок
Answer the question
In order to leave comments, you need to log in
TypeScript doesn't do that.
I can suggest normalization of complex types. Something like this:
// Заготовка для Some
interface SomeDraft {
value?: string | string[]; // Массив или значение. Может отсутствовать.
}
// Some имеет более строгий тип и как можно меньшую вариативность,
// чтобы в коде не делать проверки.
interface Some {
value: string[]; // Всегда присутствует. Всегда массив.
}
function makeSome({ value = [] }: SomeDraft): Some {
// Приводим к нормальному (более строгому) типу
return {
value: Array.isArray(value) ? value : [value],
};
}
// Здесь Some задаётся через заготовку - так проще задавать значения
// Но результат всегда более строгий - так проще значениями пользоваться
const foo = makeSome({ value: 'foo' }); // { value: ['foo'] }
foo.value.map(() => {}); // foo.value - всегда массив и TypeScript это знает
You have set some strange task. If you need a narrower type, declare it separately (and maybe even declare Some via this narrower type) and use it, or even don't specify the type at all in your example.
The following code is more than correct:
interface Some {
value: string | string[];
}
const foo = {
value: ['a', 'b'] // здесь всегда будет массив
};
foo.value.map(() => { });
function f(a: Some) {
return a;
}
f(foo);
interface Some {
value: string | string[];
}
// Тут вам стоит придумать более подходящее по смыслу название
interface WithArrayValue {
value: string[];
}
const foo: Some & WithArrayValue = {
value: ['a', 'b'] // здесь всегда будет массив
};
foo.value.map(() => { });
function f(a: Some) {
return a;
}
f(foo);
Please share why you need it. I'm not asking about a real task, but rather about demo code like the one you provided.
The only reason that comes to my mind is that you need to declare a variable that will be of a narrower type than Some, which you want to automatically infer instead of writing it by hand, but you want to be sure that the resulting type is a subtype of Some.
As one of the solutions, I can offer this:
interface Some {
value: string | string[];
}
type Extends<E, T extends E> = T;
const foo = {
value: ['a', 'b'] // здесь всегда будет массив
}
foo as Extends<Some, typeof foo>;
foo as Some
won't catch everything you need, e.g.{value: ['a', 'b', 8]}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question