Как динамически сделать ключ интерфейса обязательным (или сделать его необязательным) - PullRequest
1 голос
/ 08 июля 2020

Допустим, у меня есть тип

interface Test {
    foo: number;
    bar?: {
        name: string;
    };
}

const obj: Test;
// obj.bar is optional right now

Но скажем, у меня есть doSomething(obj), и этот метод сделает bar обязательным и установит его. Я хочу, чтобы doSomething затем возвращал новый тип, где сейчас требуется bar.

Конечно, я хочу, чтобы это было динамическое c - например, я не хочу создавать interface TestRequired и вручную вернуть этот тип.

Возможно ли это в Typescript?

Ответы [ 2 ]

4 голосов
/ 08 июля 2020

Самый простой способ изменить свойство с необязательного на обязательное - это пересечь исходный интерфейс с типом, в котором свойство содержит только это свойство, но является обязательным. Вы можете легко создать такой тип, используя Required и Pick:

declare const obj2: Test & Required<Pick<Test, 'bar'>>;
obj2.bar.name // bar is required so this is ok 

Playground Link

Также обратите внимание, что если ваша функция изменяет существующий объект, вы можете использовать утверждение пользовательского типа для изменения исходного типа:


const obj: Test = { foo: 0}
let a = obj.bar // a is  { name: string; } | undefined 

obj.bar.name // err
function doSomething(o: Test): asserts o is Test & Required<Pick<Test, 'bar'>> {
    o.bar = { name: ""}
}

doSomething(obj)

obj.bar.name // ok 

Playground Link

Вы также можете создать функцию, которая добавляет bar, но тип необходимо утверждение:


function addBar(o: Test) {
    o.bar = { name: "" }
    return o as Test & Required<Pick<Test, 'bar'>> ;
}

let obj = addBar({ foo: 0 });
obj.bar.name;

Playground Link

3 голосов
/ 08 июля 2020

Конечно. Вы можете добавить или удалить необязательный модификатор по имени свойства или обычно:

// StdLib already has the the type Partial<T> and Required<T> to make all properties of T optional or required respectively.

// Makes the named properties of T optional:
type PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

// Makes the named properties of T required:
type RequiredSome<T, K extends keyof T> = T & Required<Pick<T, K>>

Таким образом, ваш пример может выглядеть так:

interface Test {
    foo: number;
    bar?: {
        name: string;
    };
}

declare function doSomething<T extends {bar?: any}>(obj: T): RequiredSome<T, "bar">;
const obj: Test;
const other = doSomething(obj);
other.bar // bar is required!

Ссылка на игровую площадку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...