Как использовать тернарный оператор в поле вложенного объекта для проверки моего типа машинописи

#typescript #typescript-typings

Вопрос:

Я делаю здесь что-то не так или это специально?

Я хотел бы иметь возможность написать что-то подобное.

 type MyType = {
    greeting: string;
    value?: { valueType: string; value?: string };
};

function generate(name: string, input?: Partial<MyType['value']>): MyType {
    return {
        greeting: `Hello, ${name}`,
        value: input?.valueType ? input : undefined,
    };
}
 

Как вы можете видеть, я использую тернарный оператор для проверки правильности моего input объекта, но TypeScript жалуется и выдает ошибку:

Тип «неопределенный» не может быть присвоен типу «строка». (2322)


Пример игровой площадки с машинописным текстом

Ответ №1:

Сужение машинописного текста сработало должным образом, если вы переопределите свойства своего объекта. Рабочий пример :

Код :

 type MyType = {
    greeting: string;
    value?: { valueType: string; value?: string };
};

function generate(name: string, input?: MyType['value']): MyType {
    return {
       greeting: `Hello, ${name}`,
       value: input?.valueType ?  {
            valueType: input.valueType,
            value: input.value
        } : undefined,
    };
}
 

@см. https://github.com/microsoft/TypeScript/issues/29827

Комментарии:

1. Это изменило бы семантику и не позволило бы передавать input пропущенное valueType свойство, в то время как код OP допускает это. Я просто упоминаю об этом в комментарии — не совсем ясно, действительно ли OP нужно передавать объекты без valueType в функцию или нет.

2. Я также хотел бы иметь возможность вызывать функцию следующим образом: generate('Jógvan', { value: 'without a type' });

3. Теперь я лучше понимаю, каковы ваши намерения. Я отредактировал свой пост, сохранив возможность использовать подобный объект : { value: 'obj with no valueType' }

4. То, что вы предоставили, — это именно то, чего я хотел избежать, но я вижу, что это то, что нужно. Но вот кто-то показывает 3 строками, почему то, что я хочу, не поддерживается: github.com/microsoft/TypeScript/issues/…

Ответ №2:

Чтобы понять, что пошло не так, сначала давайте проверим тип в обратном положении. Это value свойство имеет следующий тип (как и ожидалось):

 { valueType: string; value?: string | undefined; } | undefined;
 

Давайте также проверим, что input?.valueType ? input : undefined дает нам:

 Partial<{
    valueType: string;
    value?: string | undefined;
}> | undefined
 

И в этом заключается проблема: вы сказали компилятору, что ожидаете valueType , что он будет иметь тип string , но то, что вы на самом деле пытались ему назначить string | undefined (очевидно, потому Partial что помощник сделал это valueType свойство необязательным).

Это Partial<T> | undefined выводится, поскольку вы также сообщили компилятору, что generate функция принимает Partial<MyType['value']> в качестве второго параметра. Итак, что вы можете с этим поделать? Без изменения семантики единственным вариантом звучания является также сделать valueType необязательным:

 type MyType = {
    greeting: string;
    value?: {
        valueType?: string;
        value?: string;
    };
};

function generate(name: string, input?: Partial<MyType['value']>): MyType {
    const value = input?.valueType ? input : undefined;
    return { greeting: `Hello, ${name}`, value }; //OK
}
 

Вероятно, это не то, что вы ищете. Однако для достижения вашей цели вам потребуется дополнительная цепочка, которая будет действовать как защита типа, так и «сопоставление» типа, о котором вы сказали компилятору Partial , чтобы удалить модификаторы. Это возможно с помощью определяемого пользователем типа защиты, который может выглядеть следующим образом:

 const withType = (val: Partial<MyType["value"]>) : val is Exclude<MyType["value"], undefined> => !!val?.valueType;

function generate(name: string, input?: Partial<MyType['value']>): MyType {
  const value = withType(input) ? input : undefined;
  return { greeting: `Hello, ${name}`, value }; //OK
}
 

Игровая площадка