Более простой способ проверки литерального типа объекта в TypeScript - PullRequest
1 голос
/ 08 апреля 2020

Я хочу Object.assign для объекта известного типа, набора свойств из литерала объекта, который должен быть того же типа. Есть ли более чистый способ сделать это в TypeScript, без фактического вызова функции идентификации или создания отдельной переменной, как предложено в этом связанном вопросе ?

type Person = {
  first?: string;
  last?: string;
}

// Overkill, actually generates code to call a function
function check<T>(value: T): T { return value; }

const dude: Person = {
  first: 'Mike',
};

Object.assign(dude, check<Person>({  // <- trying not to call a function
  last: 'Johnson',
  age: 27,  // <-- should be flagged as unknown property
}));

TL; DR - ищу способ проверки типа объекта напрямую.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Я не могу придумать «идеальное» решение для этого, которое работает при любых обстоятельствах. Большинство механизмов, которые убеждают компилятор выполнить требуемую проверку типов, также сопровождаются некоторым добавленным кодом времени выполнения (например, новым промежуточным присваиванием переменной или вызовом функции идентификации), который, как вы сказали, вам не нужен.


Одна проблема заключается в том, что TypeScript не имеет встроенных аннотаций типов. (См. microsoft / TypeScript # 7481 и microsoft / TypeScript # 13208 для обсуждения.) Вы хотели бы попросить компилятор проверить , что выражение {...} относится к типу Person, и его компилятор может пожаловаться, если его невозможно проверить. Ближайший оператор в TypeScript - это утверждение типа вида {...} as Person. Но это сообщает компилятору, что выражение {...} имеет тип Person; Вы хотите спросить .


Даже если бы у нас был встроенный оператор аннотации, есть еще одна проблема: типы объектов в TypeScript не точны . (См. microsoft / TypeScript # 12936 для обсуждения.) Типы объектов в TypeScript: open , так как вы можете добавить к ним больше свойств, не нарушая совместимость. Если у вас есть объект типа Person, вы знаете кое-что о его свойствах first и last, но вы действительно ничего не знаете о других свойствах. Тот факт, что определение Person не упоминает свойство age, не означает , что объект типа Person не может иметь свойство age. Вполне может быть такой интерфейс:

interface AgedPerson extends Person {
  age: number;
}

Характер структурный системы типов TypeScript означает, что {last: "Johnson", age: 27} является допустимым AgedPerson, даже если вы не объявляете это как таковое (и даже если AgedPerson не определено). И поскольку AgedPerson является допустимым подтипом Person, то {last: "Johnson", age: 27} также является действительным Person.

Теперь, когда люди используют литералы объекта, такие как {last: "Johnson", age: 27}, они обычно не собираются добавлять такие дополнительные свойства, поэтому в TypeScript есть функция, называемая проверка избыточного свойства , которая обрабатывает литералы объекта так, как если бы они были точных типов и жалуются, если вы добавляете неизвестные свойства. Эта функция полезна, но ее очень легко обойти. Поэтому важно упомянуть, что если вы вообще реорганизуете свой код, предупреждение о том, что age является избыточным свойством, может исчезнуть:

const ageDude = { last: 'Johnson', age: 27 };
const personDude: Person = ageDude; // no error

При этом для конкретного приведенного вами примера Я бы порекомендовал решение:

Object.assign<Person, Person>(dude, {
  last: 'Johnson',
  age: 27, // error
});

Здесь вы вручную указываете параметры типа generi c при вызове Object.assign, где первый параметр типа соответствует типу первого аргумент функции, а параметр второго типа соответствует типу аргумента второй функции. Вы хотите, чтобы компилятор рассматривал оба из них как Person, поэтому вы должны написать Object.assign<Person, Person>(...). И появляется ожидаемая ошибка избыточного свойства.


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 09 апреля 2020

Почему чувак является константой, если вы обходите его с Object.assign?

Обычно, если вы пытаетесь присвоить чувству что-то, что не является «человеком», вы получите ошибку, например

type Person = {
  first?: string;
  last?: string;
}

let dude: Person = {
  first: 'Mike',
};

dude = {  
   last: 'Johnson',
   age: 27
} // Error: Not assignable to type Person

Это проверит тип присвоения, а также покажет ошибку, если вы хотите присвоить константу.

...