Loại chỉ định: Loại 'chuỗi | undefined 'không thể gán cho kiểu' string '


100

Khi tôi đặt bất kỳ thuộc tính nào của giao diện là tùy chọn, tôi gặp lỗi như sau khi gán thành viên của nó cho một số biến khác

TS2322: Nhập 'string | undefined 'không thể gán cho kiểu' string '. Loại 'không xác định' không được gán cho loại 'chuỗi'.

interface Person {
  name?:string,
  age?:string,
  gender?:string,
  occupation?:string,
}

function getPerson(){
  let person = <Person>{name:"John"};
  return person;
}
let person: Person = getPerson();
let name1:string = person.name;//<<<Error here 

Làm cách nào để khắc phục lỗi này?

Câu trả lời:


187

Bây giờ bạn có thể sử dụng toán tử xác nhận không null ở đây chính xác cho trường hợp sử dụng của bạn.

Nó nói với TypeScript rằng mặc dù một cái gì đó trông giống như nó có thể là null, nó có thể tin tưởng bạn rằng nó không phải:

let name1:string = person.name!; 
//                            ^ note the exclamation mark here  

3
Đó chính xác là những gì tôi đang tìm kiếm!
— Shautieh

1
Cho đến khi ESLint không hạn chế việc sử dụng toán tử khẳng định không rỗng :)
— Anatoly

3
Tôi bị sốc vì một thứ cần phải tồn tại. 🤯
— GONeale

@GONeale có nhiều trường hợp trình chuyển đổi không thể tự tìm ra giá trị không thể là null. Một ví dụ là một giá trị được đặt, ví dụ như Angular, và Angular có cách riêng để đảm bảo rằng giá trị không thể rỗng.
— yannick1976

19
Đây là lời khuyên khủng khiếp! Thay vào đó, hãy giúp trình biên dịch tìm ra nó. Thêm dấu kiểm trước khi truy cập thuộc tính, nơi bạn có thể ném hoặc trả lại nếu tên không được đặt.
— geon

57

Để tránh lỗi biên dịch tôi đã sử dụng

let name1:string = person.name || '';

Và sau đó xác thực chuỗi trống.


1
Điều gì sẽ xảy ra nếu nó không phải là một chuỗi mà là một đối tượng?
— Anatoly

1
Nếu nó là một đối tượng thì thay vì '' nó sẽ là {}
— Kriti

Đây là điều bạn có thể làm khi đang xâu chuỗi các giá trị và bạn gặp phải lỗi như thế nàyOptional chain expressions can return undefined by design - using a non-null assertion is unsafe and wrong.
— tHeSiD

26

Tôi biết đây là câu trả lời hơi muộn nhưng có một cách khác ngoài câu trả lời của yannick https://stackoverflow.com/a/57062363/6603342 để sử dụng! là truyền nó dưới dạng chuỗi do đó nói với TypeScript tôi chắc chắn rằng đây là một chuỗi do đó chuyển đổi

let name1:string = person.name;//<<<Error here 

đến

let name1:string = person.name as string;

Điều này sẽ làm cho lỗi biến mất nhưng nếu tình cờ đây không phải là một chuỗi, bạn sẽ gặp phải lỗi thời gian chạy, đây là một trong những lỗi mà chúng tôi đang sử dụng TypeScript để đảm bảo rằng kiểu khớp và tránh những lỗi như vậy tại thời điểm biên dịch .


Điều này có thể làm cho lỗi biến mất, nhưng nó không bao giờ thay đổi loại thực tế của biến.
— Mansi

Tôi xin lỗi nhưng tôi nghĩ rằng bạn khá nhầm lẫn ở đó, vì tôi đã đề cập điều này thực tế sẽ thay đổi kiểu vì nó sẽ ném ra một ngoại lệ thời gian chạy nếu kiểu đó không phải là một chuỗi hoặc không có phương thức toString. Thao tác này sẽ truyền bất cứ thứ gì ở đó thành một chuỗi, tức là bạn có một số, nó sẽ cố gắng gọi hàm .toString của bất kỳ thứ gì bạn có ở đó.
— Harry

Nhưng đó sẽ không phải là cách chính xác đúng, nói rằng nếu tên của tôi có số "0" trong đó, nó sẽ ẩn nó thành chuỗi ... Thay vì nó sẽ tạo ra một lỗi và nói tên không hợp lệ. Cá nhân tôi sẽ không sử dụng typecast này và đặc biệt kiểm tra loại được truyền vào đối tượng .. nhưng tất cả chúng ta đều có các phong cách mã hóa khác nhau, hãy mở để thảo luận thêm về cùng một thứ
— Mansi

Có nhưng điều này hoàn toàn nằm ngoài ngữ cảnh của câu hỏi mà câu trả lời này đã được đưa ra. Chúng tôi không biết liệu đây có phải là một biểu mẫu hay không nếu không có các bước để lọc ra trước đó. Ngoài ra, những gì bạn đang đề xuất sẽ không thể xảy ra ở giai đoạn đó nếu không có một số cách giải quyết thực sự bẩn thỉu.
— Harry

Không cần giải pháp thay thế, chỉ cần một lần kiểm tra trước khi bạn cố gắng truy cập biến. Cả hai trường hợp sẽ được xử lý dễ dàng, lỗi sẽ biến mất và mã của bạn sẽ an toàn hơn. Chỉ cần thử nó :)
— Mansi

21

Kể từ TypeScript 3.7, bạn có thể sử dụng toán tử liên kết nullish ?? . Bạn có thể coi tính năng này như một cách để "quay trở lại" giá trị mặc định khi xử lý null hoặc undefined

let name1:string = person.name ?? '';

Các ??nhà điều hành có thể thay thế công dụng của ||khi cố gắng sử dụng một giá trị mặc định và có thể được sử dụng khi giao dịch với các phép toán luận, số, vv nơi ||không thể được sử dụng.

Kể từ TypeScript 4, bạn có thể sử dụng ??=toán tử gán a ??= bđể thay thế choa = a ?? b;


7

cố gắng tìm hiểu trước giá trị thực tế là bao nhiêu. Nếu personcó giá trị name, hãy gán nó cho name1, nếu không thì gán undefined.

let name1: string = (person.name) ? person.name : undefined;

2
hmmm. Điều đó sẽ quá dài nếu tôi muốn làm nhiều bài tập. Có cách nào để tắt cảnh báo cụ thể này không?
— asdasd

Rất tiếc là không ngoại trừ bạn thực hiện namebắt buộc bằng cách xóa dấu chấm hỏi.
— Lynx 242

Tái bút: Bạn sử dụng phiên bản TypeScript nào? Tôi sử dụng 3.2.4 và không gặp phải Thông báo này. Trong lớp thử nghiệm của tôi, mã được biên dịch cẩn thận.
— Lynx 242

cùng một phiên bản. Tôi gặp lỗi này trong webstorm nhưng không phải trong vscode
— asdasd

Điều đó thật kỳ lạ, bởi vì tôi sử dụng IntelliJ được cho là tương tự như WebStorm khi áp dụng các quy tắc TS ?!
— Lynx 242

5

Một cách sẵn sàng hơn cho sản xuất để xử lý điều này là thực sự đảm bảo rằng namenó hiện diện. Giả sử đây là một ví dụ tối thiểu về một dự án lớn hơn mà một nhóm người tham gia, bạn không biết getPersonsẽ thay đổi như thế nào trong tương lai.

if (!person.name) {
    throw new Error("Unexpected error: Missing name");
}

let name1: string = person.name;

Ngoài ra, bạn có thể nhập name1là string | undefinedvà xử lý các trường hợp undefinedgiảm thêm. Tuy nhiên, thông thường tốt hơn là xử lý các lỗi không mong muốn sớm hơn.

Bạn cũng có thể cho phép TypeScript suy ra kiểu bằng cách bỏ qua kiểu rõ ràng: Ví dụ : điều let name1 = person.namenày sẽ vẫn ngăn name1việc được gán lại thành một số.


3

Đây là một cách nhanh chóng để biết những gì đang xảy ra:

Khi bạn làm như sau:

Tên? : chuỗi

Bạn đã nói với TypeScript nó là tùy chọn. Tuy nhiên, khi bạn làm:

let name1 : string = person.name; //<<<Error here 

Bạn đã không để nó một sự lựa chọn. Bạn cần có một Liên minh trên đó phản ánh loại không xác định:

let name1 : string | undefined = person.name; //<<<No error here 

Sử dụng câu trả lời của bạn, tôi đã có thể phác thảo những điều sau đây về cơ bản là Giao diện, Lớp và Đối tượng. Tôi thấy cách tiếp cận này đơn giản hơn, đừng bận tâm nếu bạn không làm.

// Interface
interface iPerson {
    fname? : string,
    age? : number,
    gender? : string,
    occupation? : string,
    get_person?: any
}

// Class Object
class Person implements iPerson {
    fname? : string;
    age? : number;
    gender? : string;
    occupation? : string;
    get_person?: any = function () {
        return this.fname;
    }
}

// Object literal
const person1 : Person = {
    fname : 'Steve',
    age : 8,
    gender : 'Male',
    occupation : 'IT'  
}

const p_name: string | undefined = person1.fname;

// Object instance 
const person2: Person = new Person();
person2.fname = 'Steve';
person2.age = 8;
person2.gender = 'Male';
person2.occupation = 'IT';

// Accessing the object literal (person1) and instance (person2)
console.log('person1 : ', p_name);
console.log('person2 : ', person2.get_person());

2

Bạn đang cố gắng đặt biến name1, kiểu phù hợp được đặt là chuỗi nghiêm ngặt (nó PHẢI là chuỗi) với giá trị từ trường đối tượng name, kiểu giá trị phù hợp được đặt là chuỗi tùy chọn (có thể là chuỗi hoặc không xác định, vì dấu hỏi). Nếu bạn thực sự cần hành vi này, bạn phải thay đổi kiểu name1như thế này:

let name1: string | undefined = person.name;

Và nó sẽ ổn thôi;


0

Lưu ý rằng nếu biến đến từ một mảng hoặc cấu trúc hủy, bạn có thể cung cấp các giá trị mặc định:

const { DB_HOST = "localhost", DB_PORT: "5432" } = process.env

db.connect(DB_HOST, DB_PORT);
const connectToDb = (host = "localhost", port: "5432") => db.connect(host, port);


0

Bạn có thể sử dụng NonNullableLoại Tiện ích:

Thí dụ

type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>;  // string[]

Tài liệu .


-1

Giải pháp 1: Loại bỏ định nghĩa kiểu rõ ràng

Vì getPersonđã trả về a Personkèm theo tên, chúng ta có thể sử dụng kiểu suy luận.

function getPerson(){
  let person = {name:"John"};
  return person;
}

let person = getPerson();

Nếu chúng ta xác định, person: Personchúng ta sẽ mất một phần thông tin. Chúng ta biết getPersontrả về một đối tượng có thuộc tính không tùy chọn được gọi name, nhưng việc mô tả nó như Personthế sẽ đưa tính tùy chọn trở lại.

Giải pháp 2: Sử dụng một định nghĩa chính xác hơn

type Require<T, K extends keyof T> = T & {
  [P in K]-?: T[P]
};

function getPerson() {
  let person = {name:"John"};
  return person;
}

let person: Require<Person, 'name'> = getPerson();
let name1:string = person.name;

Giải pháp 3: Thiết kế lại giao diện của bạn

Một hình dạng trong đó tất cả các thuộc tính là tùy chọn được gọi là kiểu yếu và thường là một chỉ báo của thiết kế xấu. Nếu chúng tôi tạo ra namemột thuộc tính bắt buộc, vấn đề của bạn sẽ biến mất.

interface Person {
  name:string,
  age?:string,
  gender?:string,
  occupation?:string,
}

-14

Có cùng một vấn đề.

Tôi phát hiện ra rằng các kịch bản phản ứng thêm "strict": truevào tsconfig.json.

Sau khi tôi loại bỏ nó, mọi thứ hoạt động tốt.

Biên tập

Cần cảnh báo rằng việc thay đổi thuộc tính này có nghĩa là bạn:

không được cảnh báo về các lỗi thời gian chạy tiềm ẩn nữa.

như đã được PaulG chỉ ra trong các bình luận! Cảm ơn bạn :)

"strict": falseChỉ sử dụng nếu bạn hiểu đầy đủ về những gì nó ảnh hưởng!


9
Điều này có thể 'làm việc'. Nhưng nó chỉ hoạt động khi bạn không được cảnh báo về các lỗi thời gian chạy tiềm ẩn nữa. Tôi muốn khuyến khích nghiên cứu về những gì các kiểm tra nghiêm ngặt trong nguyên cảo làm: medium.com/webhint/going-strict-with-typescript-be3f3f7e3295
— PaulG

5
Tôi nên đề cập rằng OP đã hỏi, "Làm cách nào để khắc phục lỗi này?" không phải, "Làm cách nào để khắc phục sự cố này?"
— devinbost

Chỉ cần thêm tên: string = undefined (theo khuyến nghị của các gói như json2typescript) sẽ gây ra lỗi 2322 trừ khi bạn tắt nghiêm ngặt, đó là điều mà hầu hết mọi người sẽ cần làm. Câu trả lời được chấp nhận này là rõ ràng, chính xác và xứng đáng được nhiều phiếu bầu hơn nữa.
— AUSTX_RJL
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.