'будь-який' проти 'об’єкта'


210

Я переглядаю код TypeScript і помітив, що вони використовують:

interface Blablabla {

   field: Object;

}

Яка вигода від використання Objectvs any, як у:

interface Blablabla {

  field: any;

}

Відповіді:


202

Objectє більш обмежувальним, ніж any. Наприклад:

let a: any;
let b: Object;

a.nomethod(); // Transpiles just fine
b.nomethod(); // Error: Property 'nomethod' does not exist on type 'Object'.

ObjectКлас не має nomethod()функції, тому transpiler буде генерувати помилку говорить вам саме це. Якщо ви використовуєте anyзамість цього, ви в основному говорите транспілеру, що все йде, ви не надаєте жодної інформації про те, що зберігається a- це може бути все що завгодно! І тому транспілятор дозволить вам робити все, що завгодно, з чимось визначеним як any.

Так коротше

  • any може бути будь-що (ви можете викликати будь-який метод тощо на ньому без помилок компіляції)
  • Objectрозкриває функції та властивості, визначені в Objectкласі.

284

Трохи старий, але не завадить додавати нотатки.

Коли ти пишеш щось подібне

let a: any;
let b: Object;
let c: {};
  • a не має інтерфейсу, він може бути чим завгодно, компілятор нічого не знає про своїх членів, тому під час доступу / присвоєння йому та його членам не проводиться перевірка типу. В основному, ви говорите компілятору " відступати, я знаю, що роблю, тому просто довірте мені ";
  • b має інтерфейс Object, тому ТОЛЬКІ члени, визначені в цьому інтерфейсі, доступні для b . Це все ще JavaScript, тому все поширюється на Object;
  • c розширює Object, як і все в TypeScript, але не додає членів. Оскільки сумісність типів у TypeScript базується на структурному підтипуванні, а не номінальному підтипізації, c в кінцевому підсумку є таким же, як b, оскільки вони мають однаковий інтерфейс: інтерфейс Object.

І саме тому

a.doSomething(); // Ok: the compiler trusts you on that
b.doSomething(); // Error: Object has no doSomething member
c.doSomething(); // Error: c neither has doSomething nor inherits it from Object

і чому

a.toString(); // Ok: whatever, dude, have it your way
b.toString(); // Ok: toString is defined in Object
c.toString(); // Ok: c inherits toString from Object

Так Objectі {}є еквівалентами в TypeScript.

Якщо ви оголошуєте такі функції

function fa(param: any): void {}
function fb(param: Object): void {}

з наміром прийняти що-небудь за парам (можливо, ви збираєтеся перевірити типи під час виконання, щоб вирішити, що з ним робити), пам’ятайте про це

  • всередині fa компілятор дозволить вам робити все, що завгодно, з парам ;
  • всередині fb компілятор дозволить вам посилатися лише на членів Об'єкта .

Варто зауважити, що якщо парам повинен приймати кілька відомих типів, кращим підходом є оголошення його за допомогою типів об'єднання, як у

function fc(param: string|number): void {}

Очевидно, що правила OO успадкування все ще діють, тому, якщо ви хочете прийняти екземпляри похідних класів і обробити їх на основі їх базового типу, як у

interface IPerson {
    gender: string;
}

class Person implements IPerson {
    gender: string;
}

class Teacher extends Person {}

function func(person: IPerson): void {
    console.log(person.gender);
}

func(new Person());     // Ok
func(new Teacher());    // Ok
func({gender: 'male'}); // Ok
func({name: 'male'});   // Error: no gender..

базовий тип - це спосіб, а не будь-який . Але це ОО, поза межами сфери, я просто хотів уточнити, що будь-який слід використовувати лише тоді, коли ви не знаєте, що відбувається, а для чого-небудь іншого слід анотувати правильний тип.

ОНОВЛЕННЯ:

Машинопис 2.2 доданий objectтип, який визначає , що значення є непрімітівним: (тобто не number, string, boolean, symbol, undefined, або null).

Розглянемо функції, визначені як:

function b(x: Object) {}
function c(x: {}) {}
function d(x: object) {}

xматиме однакові доступні властивості у всіх цих функціях, але помилка типу викликає dпримітив:

b("foo"); //Okay
c("foo"); //Okay
d("foo"); //Error: "foo" is a primitive

2
Хтось знає, чому вони вирішили додати {}тоді, якщо вони вже були Object? (або навпаки, що б не сталося першим) Повинна бути незначна різниця, правда?
— CletusW

4
{}- це звичайний спосіб визначення (вбудованих) інтерфейсів, лише в цьому випадку ви визначаєте інтерфейс без членів. Незначна різниця добре пояснюється у відповіді: " {}розширюється Object, як і все, що є в TypeScript".
— DanielM

7
Я хочу, щоб ви проголосували за рядок. Тож, в основному, коли ви не знаєте типу, перейдіть anyі виконайте перевірку типу виконання. Чи не слід використовувати any, замість того, щоб використовувати об'єднання типів ви перевіряєте проти: TypeA|InterfaceB|string. Якщо у вас також є випадок за замовчуванням для невідомого типу, додайте {}або Objectдо об'єднання.
— ILMTitan

Документи машинопису іноді плутають, наприклад, But variables of type Object only allow you to assign any value to them - you can’t call arbitrary methods on them, even ones that actually exist:змусили мене думати, що навіть дзвінки toStringзаборонені, коли насправді я думаю, що вони мали намір сказати, exist at runtimeпрочитавши відповідь.
— Ольга

24

any щось типове для TypeScript, це досить добре пояснюється відповіддю Алекса.

Objectвідноситься до objectтипу JavaScript . Зазвичай використовується як {}або іноді new Object. Більшість речей у javascript сумісні з типом даних об'єкта, оскільки вони успадковують його. Але anyце машинопис специфічні і сумісний з усім в обох напрямках (НЕ на основі успадкування). наприклад:

var foo:Object; 
var bar:any;
var num:number;

foo = num; // Not an error
num = foo; // ERROR 

// Any is compatible both ways 
bar = num;
num = bar;  

1
Ваша відповідь є досить невиразною, і це змішується, Objectі objectце різні типи в TypeScript.
— m93a

@ m93a: Чи можете ви розширити, в чому різниця між Objectі objectв TS?
— Олександр Абакумов

4
Це , мабуть, найкраще джерело, щоб дізнатися різницю. Основний момент полягає в тому, що objectце тип для всього, що не є примітивним, в той час Objectяк це інтерфейс, який містить загальні речі, подібні toStringта інше . Це число 42було б, Objectале не було object.
— m93a

20

На відміну від .NET, де всі типи походять від "об'єкта", у TypeScript усі типи походять від "будь-якого". Я просто хотів додати це порівняння, оскільки я думаю, що це буде загальним, оскільки більше розробників .NET намагаються TypeScript спробувати.


16

Здається, об'єкт є більш конкретною декларацією, ніж будь-яка. З специфікації TypeScript (розділ 3):

Всі типи в TypeScript є підтипами одного верхнього типу, що називається "Будь-який тип". Будь-яке ключове слово посилається на цей тип. Будь-який тип - це один тип, який може представляти будь-яке значення JavaScript без обмежень. Усі інші типи класифікуються як примітивні типи, типи об'єктів або параметри типу. Ці типи вводять різні статичні обмеження на їх значення.

Також:

Будь-який тип використовується для представлення будь-якого значення JavaScript. Значення типу "Будь-який" підтримує ті ж операції, що і значення в JavaScript, і мінімальна статична перевірка типу виконується для операцій з "Будь-які значення". Зокрема, до будь-яких імен можна отримати доступ через значення Any, а будь-які значення можна викликати як функції або конструктори з будь-яким списком аргументів.

Об'єкти не допускають однакової гнучкості.

Наприклад:

var myAny : any;

myAny.Something(); // no problemo

var myObject : Object;

myObject.Something(); // Error: The property 'Something' does not exist on value of type 'Object'.

0

Додавання відповіді Алекса та спрощення її:

Об'єкти є більш суворими з їх використанням, а отже, дає програмісту більше часу на компіляцію на "оцінку" потужності, а отже, у багатьох випадках забезпечують більшу "перевірку можливостей" і можуть запобігти будь-яким витокам, тоді як будь-який є більш загальним терміном і багато компіляції Таким чином, час перевірки може бути ігнорований.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.