Пустой объект Typescript для типизированной переменной

88

Скажем, у меня есть:

type User = {
...
}

Я хочу создать новый объект, userно сделать его пустым:

const user: User = {}; // This fails saying property XX is missing
const user: User = {} as any; // This works but I don't want to use any

Как мне это сделать? Я не хочу, чтобы переменная была null.

Коуша
источник
15
Либо вы хотите userиметь тип, User | {}либо Partial<User>, либо вам нужно переопределить Userтип, чтобы разрешить пустой объект. Прямо сейчас компилятор правильно сообщает вам, что userэто не файл User.
jcalz

Ответы:

186

Предостережения

Вот две достойные оговорки из комментариев.

Либо вы хотите, чтобы пользователь относился к типу User | {}или Partial<User>, либо вам нужно переопределить Userтип, чтобы разрешить пустой объект. Прямо сейчас компилятор правильно сообщает вам, что пользователь не является пользователем. -jcalz

Я не думаю, что это следует считать правильным ответом, потому что он создает несогласованный экземпляр типа, подрывая всю цель TypeScript. В этом примере свойство Usernameоставлено неопределенным, а в аннотации типа указано, что оно не может быть неопределенным. -Ian Liu Rodrigues

Ответ

Одна из целей дизайна TypeScript - «найти баланс между правильностью и производительностью». Если это будет продуктивно для вас, используйте утверждения типа, чтобы создать пустые объекты для типизированных переменных.

type User = {
    Username: string;
    Email: string;
}

const user01 = {} as User;
const user02 = <User>{};

user01.Email = "foo@bar.com";

Вот вам рабочий пример .

Вот утверждения типа, работающие с предложением.

Шон Латтин
источник
9
Спасибо! Это решает проблему! Это должно быть отмечено как правильный ответ ...
Кокодоко
3
Я не думаю, что это следует считать правильным ответом, потому что он создает несогласованный экземпляр типа, подрывая всю цель TypeScript. В этом примере свойство Usernameоставлено неопределенным, а в аннотации типа указано, что оно не может быть неопределенным.
Ян Лю Родригес
2
Хороший замечание @IanLiuRodrigues. Я добавил к ответу несколько оговорок.
Shaun Luttin
1
@IanLiuRodrigues Одна из целей TypeScript - уравновесить правильность и производительность, так что сказать, что это подрывает всю цель TypeScript, немного экстремально. github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
Shaun Luttin
22

На самом деле зависит от того, что вы пытаетесь сделать. Типы - это документация в машинописном тексте, поэтому вы хотите показать намерение о том, как эта вещь должна использоваться при создании типа.

Вариант 1. Если у пользователей могут быть некоторые, но не все атрибуты в течение их жизни

Сделайте все атрибуты необязательными

type User = {
  attr0?: number
  attr1?: string
}

Вариант 2. Если переменные, содержащие пользователей, могут начинаться с нуля

type User = {
...
}
let u1: User = null;

Хотя на самом деле здесь, если цель состоит в том, чтобы объявить объект User до того, как станет известно, что ему будет назначено, вы, вероятно, захотите обойтись let u1:Userбез какого-либо назначения.

Вариант 3: что вы, вероятно, захотите

На самом деле предпосылка машинописного текста - убедиться, что вы соответствуете ментальной модели, которую вы обрисовываете в типах, чтобы избежать ошибок. Если вы хотите добавлять элементы к объекту по одному, это привычка, которую TypeScript пытается заставить вас не делать.

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

let attr1: number = ...
let attr2: string = ...
let user1: User = {
  attr1: attr1,
  attr2: attr2
}
pixelpax
источник
Не уверен, что это то, к чему он идет, или нет, но возможно, что мы говорим об отдельном аргументе под названием UserAttributes или о чем-то, что обрабатывает входящие параметры. Это может быть неприемлемый пользовательский объект, поэтому его можно определить отдельно.
откроется
Это не должен быть принятым ответом. См. Сообщение Шона Латтина ниже.
thargenediad
2

вы можете сделать это, как показано ниже в машинописном тексте

 const _params = {} as any;

 _params.name ='nazeh abel'

поскольку typescript не ведет себя как javascript, поэтому мы должны сделать тип таким же, как и любой, иначе он не позволит вам динамически назначать свойство объекту

Nazehs
источник
2

Обратите внимание, что использование const user = {} as UserTypeпросто обеспечивает intellisense, но во время выполнения userявляется пустым объектом {}и не имеет свойства внутри. это значит user.Emailдаст undefinedвместо""

type UserType = {
    Username: string;
    Email: string;
}

Итак, используйте classwith constructorдля фактического создания объектов со свойствами по умолчанию.

type UserType = {
  Username: string;
  Email: string;
};

class User implements UserType {
  constructor() {
    this.Username = "";
    this.Email = "";
  }

  Username: string;
  Email: string;
}

const myUser = new User();
console.log(myUser); // output: {Username: "", Email: ""}
console.log("val: "+myUser.Email); // output: ""

Вы также можете использовать interfaceвместоtype

interface UserType {
  Username: string;
  Email: string;
};

... и остальной код остается прежним.


Фактически, вы даже можете пропустить эту constructorчасть и использовать ее так:

class User implements UserType {
      Username = ""; // will be added to new obj
      Email: string; // will not be added
}

const myUser = new User();
console.log(myUser); // output: {Username: ""}
ГорвГойл
источник
1

Если вы объявляете литерал пустого объекта, а затем назначаете значения позже, вы можете считать эти значения необязательными (могут или не могут быть там), поэтому просто введите их как необязательные с вопросительным знаком:

type User = {
    Username?: string;
    Email?: string;
}
КаталинБерта
источник