简体   繁体   English

类型化变量的 TypeScript 空对象

[英]TypeScript empty object for a typed variable

Say I have:说我有:

type User = {
  ...
}

I want to create a new user but set it to be an empty object:我想创建一个新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

How do I do this?我该怎么做呢? I don't want the variable to be null .我不希望变量为null

Caveats注意事项

Here are two worthy caveats from the comments.以下是评论中的两个有价值的警告。

Either you want user to be of type User | {}您希望用户的类型为User | {} User | {} or Partial<User> , or you need to redefine the User type to allow an empty object. User | {}Partial<User> ,或者您需要重新定义User类型以允许空对象。 Right now, the compiler is correctly telling you that user is not a User.现在,编译器正确地告诉您用户不是用户。 jcalz jcalz

I don't think this should be considered a proper answer because it creates an inconsistent instance of the type, undermining the whole purpose of TypeScript.我认为这不应该被视为一个正确的答案,因为它创建了一个不一致的类型实例,破坏了 TypeScript 的整个目的。 In this example, the property Username is left undefined, while the type annotation is saying it can't be undefined.在此示例中,属性Username未定义,而类型注释表示它不能未定义。 Ian Liu Rodrigues Ian Liu Rodrigues

Answer回答

One of the design goals of TypeScript is to "strike a balance between correctness and productivity." TypeScript设计目标之一“在正确性和生产力之间取得平衡”。 If it will be productive for you to do this, use Type Assertions to create empty objects for typed variables.如果这样做对您有帮助,请使用类型断言为类型变量创建空对象。

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

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

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

Here is a working example for you .这是一个工作示例

以下是使用建议的类型断言。

Really depends on what you're trying to do.真的取决于你想要做什么。 Types are documentation in typescript, so you want to show intention about how this thing is supposed to be used when you're creating the type.类型是打字稿中的文档,因此您想表明在创建类型时应该如何使用这个东西的意图。

Option 1: If Users might have some but not all of the attributes during their lifetime选项 1:如果用户在其生命周期中可能拥有部分而非全部属性

Make all attributes optional使所有属性可选

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

Option 2: If variables containing Users may begin null选项 2:如果包含用户的变量可能以 null 开头

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

Though, really, here if the point is to declare the User object before it can be known what will be assigned to it, you probably want to do let u1:User without any assignment.虽然,实际上,如果重点是在知道将分配给它的内容之前声明 User 对象,您可能希望在没有任何分配的情况下执行let u1:User

Option 3: What you probably want选项 3:您可能想要的

Really, the premise of typescript is to make sure that you are conforming to the mental model you outline in types in order to avoid making mistakes.确实,打字稿的前提是确保您符合您在类型中勾勒出的心智模型,以避免犯错误。 If you want to add things to an object one-by-one, this is a habit that TypeScript is trying to get you not to do.如果你想一个一个地向一个对象添加东西,这是 TypeScript 试图让你不要这样做的习惯。

More likely, you want to make some local variables, then assign to the User-containing variable when it's ready to be a full-on User.更有可能的是,您想要创建一些局部变量,然后当它准备好成为一个完整的用户时分配给包含用户的变量。 That way you'll never be left with a partially-formed User.这样你就永远不会留下一个部分形成的用户。 Those things are gross.那些东西太恶心了。

let attr1: number = ...
let attr2: string = ...
let user1: User = {
  attr1: attr1,
  attr2: attr2
}

In my case Record<string, never> helps, it was recommended by eslint在我的例子Record<string, never>有帮助,这是 eslint 推荐的Eslint 推荐

Note that using const user = {} as UserType just provides intellisense but at runtime user is empty object {} and has no property inside.请注意,使用const user = {} as UserType仅提供智能感知,但在运行时user是空对象{}并且内部没有属性。 that means user.Email will give undefined instead of ""这意味着user.Email将给出undefined而不是""

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

So, use class with constructor for actually creating objects with default properties.因此,使用带有constructor class来实际创建具有默认属性的对象。

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: ""

You can also use interface instead of type您也可以使用interface而不是type

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

...and rest of code remains same. ...其余代码保持不变。


Actually, you can even skip the constructor part and use it like this:实际上,您甚至可以跳过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: ""}

you can do this as below in typescript您可以在打字稿中按如下方式执行此操作

 const _params = {} as any;

 _params.name ='nazeh abel'

since typescript does not behave like javascript so we have to make the type as any otherwise it won't allow you to assign property dynamically to an object由于打字稿的行为不像 javascript,所以我们必须将类型设为任何类型,否则它将不允许您将属性动态分配给对象

If you declare an empty object literal and then assign values later on, then you can consider those values optional (may or may not be there), so just type them as optional with a question mark:如果您声明一个空对象字面量,然后稍后分配值,那么您可以将这些值视为可选的(可能存在也可能不存在),因此只需将它们键入为带有问号的可选:

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

What i wanted is intellisense help for a chain of middlewares.我想要的是对中间件链的intellisense帮助。 Record<string, never> worked for me. Record<string, never>对我有用。

type CtxInitialT = Record<string, never>;
type Ctx1T = CtxInitialT & {
  name: string;
};
type Ctx2T = Ctx1T & {
  token: string;
};

cont ctx: CtxInitialT = {};
// ctx.name = ''; // intellisense error Type 'string' is not assignable to type 'never'
cont ctx1: Ctx1T = middleware1AugmentCtx(ctx);
// ctx1.name = 'ddd'; // ok
// ctx1.name1 = ''; // intellisense error Type 'string' is not assignable to type 'never'
cont ctx2: Ctx2T = middleware2AugmentCtx(ctx1);
// ctx2.token = 'ttt'; // ok
// ctx2.name1 = ''; // intellisense error Type 'string' is not assignable to type 'never'
user: USER

this.user = ({} as USER)

Record<Keys,Type>记录<键,类型>

Constructs an object type whose property keys are Keys and whose property values are Type.构造一个对象类型,其属性键为 Keys,属性值为 Type。 This utility can be used to map the properties of a type to another type.此实用程序可用于将一种类型的属性映射到另一种类型。

 const user:Record<string,string>={}

空对象可以写为Record<string,never> ,因此实际上您的用户类型是空对象或用户

const user : User | Record<string, never> = {};

In case of的情况下

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

you can declare an empty object or only one field(for example, only Username);您可以声明一个空对象或只有一个字段(例如,只有用户名); in that case, you will not have an error, which can be a problem.在那种情况下,你不会有错误,这可能是一个问题。

I will prefer more {} as User version.我更喜欢更多 {} 作为User版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM