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 Assertionsเพื่อสร้างอ็อบเจ็กต์ว่างสำหรับตัวแปรที่พิมพ์

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

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

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

นี่คือตัวอย่างการทำงานสำหรับคุณ

นี่คือการยืนยันประเภทที่ทำงานร่วมกับข้อเสนอแนะ


9
ขอขอบคุณ! วิธีนี้แก้ได้! ควรทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง ...
Kokodoko

3
ฉันไม่คิดว่านี่ควรถือเป็นคำตอบที่เหมาะสมเพราะมันสร้างอินสแตนซ์ของประเภทที่ไม่สอดคล้องกันซึ่งทำลายวัตถุประสงค์ทั้งหมดของ TypeScript ในตัวอย่างนี้คุณสมบัติUsernameจะถูกปล่อยทิ้งไว้โดยไม่ได้กำหนดในขณะที่คำอธิบายประกอบประเภทบอกว่าไม่สามารถระบุไม่ได้
Ian Liu Rodrigues

2
จุดดี @IanLiuRodrigues ฉันเพิ่มคำเตือนบางอย่างในคำตอบ
Shaun Luttin

1
@IanLiuRodrigues หนึ่งในเป้าหมายของ TypeScript คือการสร้างความสมดุลให้กับความถูกต้องกับผลผลิตดังนั้นการบอกว่าสิ่งนี้ทำลายวัตถุประสงค์ทั้งหมดของ TypeScriptนั้นค่อนข้างรุนแรง github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
Shaun Luttin

22

ขึ้นอยู่กับสิ่งที่คุณพยายามทำจริงๆ ประเภทเป็นเอกสารใน typescript ดังนั้นคุณต้องการแสดงเจตนาว่าควรใช้สิ่งนี้อย่างไรเมื่อคุณสร้างประเภท

ตัวเลือกที่ 1: หากผู้ใช้อาจมีแอตทริบิวต์บางส่วน แต่ไม่ใช่ทั้งหมดในช่วงอายุของพวกเขา

ทำให้แอตทริบิวต์ทั้งหมดเป็นทางเลือก

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

ตัวเลือกที่ 2: หากตัวแปรที่มีผู้ใช้อาจเริ่มเป็นค่าว่าง

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

แม้ว่าจริงๆแล้วที่นี่ถ้าประเด็นคือการประกาศวัตถุผู้ใช้ก่อนที่จะสามารถรู้ได้ว่าจะกำหนดอะไรให้คุณอาจต้องการทำ let u1:Userโดยไม่ต้องมีการมอบหมายใด ๆ

ตัวเลือกที่ 3: สิ่งที่คุณอาจต้องการ

จริงๆแล้วหลักฐานของ typescript คือเพื่อให้แน่ใจว่าคุณปฏิบัติตามแบบจำลองทางจิตที่คุณร่างไว้ในประเภทต่างๆเพื่อหลีกเลี่ยงการผิดพลาด หากคุณต้องการเพิ่มสิ่งต่างๆให้กับวัตถุทีละชิ้นนี่เป็นนิสัยที่ TypeScript พยายามไม่ให้คุณทำ

เป็นไปได้มากว่าคุณต้องการสร้างตัวแปรในระบบจากนั้นกำหนดให้กับตัวแปรที่มีผู้ใช้เมื่อพร้อมที่จะเป็นผู้ใช้เต็มรูปแบบ ด้วยวิธีนี้คุณจะไม่เหลือผู้ใช้ที่สร้างขึ้นบางส่วน สิ่งเหล่านั้นเป็นขั้นต้น

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

ไม่แน่ใจว่านี่คือสิ่งที่เขาต้องการหรือไม่ แต่เป็นไปได้ว่าเรากำลังพูดถึงอาร์กิวเมนต์แยกต่างหากที่เรียกว่า UserAttributes หรือสิ่งที่จัดการกับพารามิเตอร์ขาเข้า มันอาจไม่ใช่วัตถุของผู้ใช้ที่ยอมรับได้ดังนั้นจึงสามารถกำหนดแยกกันได้
unflores

นี่ไม่ควรเป็นคำตอบที่ยอมรับได้ โปรดดูโพสต์ของ Shaun Luttin ด้านล่าง
thargenediad

2

คุณสามารถทำได้ดังต่อไปนี้ใน typescript

 const _params = {} as any;

 _params.name ='nazeh abel'

เนื่องจาก typescript ไม่ทำงานเหมือน javascript ดังนั้นเราจึงต้องสร้าง type เป็นอย่างอื่นไม่อนุญาตให้คุณกำหนดคุณสมบัติแบบไดนามิกให้กับวัตถุ


2

โปรดทราบว่าการใช้const user = {} as UserTypeเพียงแค่ให้ intellisense แต่ที่รันไทม์userเป็นวัตถุว่างเปล่า{}และไม่มีคุณสมบัติอยู่ภายใน นั่นหมายความว่าuser.Emailจะให้undefinedแทน""

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

ดังนั้นใช้classกับ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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.