„dowolny” a „obiekt”


210

Patrzę na kod TypeScript i zauważyłem, że używają:

interface Blablabla {

   field: Object;

}

Jaka jest korzyść z używania Objectvs any, jak w:

interface Blablabla {

  field: any;

}

Odpowiedzi:


202

Objectjest bardziej restrykcyjny niż any. Na przykład:

let a: any;
let b: Object;

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

ObjectKlasa nie posiada nomethod()funkcji, dlatego transpiler wygeneruje błąd informujący dokładnie to. Jeśli użyjesz anyzamiast tego, zasadniczo mówisz transpilatorowi, że coś idzie, nie podajesz żadnych informacji o tym, co jest przechowywane a- może być cokolwiek! A zatem transpiler pozwoli ci robić, co chcesz, z czymś określonym jako any.

Krótko mówiąc

  • any może być dowolna (możesz wywołać dowolną metodę itp. bez błędów kompilacji)
  • Objectujawnia funkcje i właściwości zdefiniowane w Objectklasie.

284

Trochę stary, ale nie zaszkodzi dodać kilka notatek.

Kiedy piszesz coś takiego

let a: any;
let b: Object;
let c: {};
  • a nie ma interfejsu, może być czymkolwiek, kompilator nic nie wie o swoich członkach, więc nie jest przeprowadzane sprawdzanie typu podczas uzyskiwania dostępu / przypisywania zarówno do niego, jak i jego członków. Zasadniczo mówisz kompilatorowi: „ wycofaj się, wiem, co robię, więc zaufaj mi ”;
  • b ma interfejs Object, więc TYLKO członkowie zdefiniowani w tym interfejsie są dostępni dla b . Nadal jest JavaScript, więc wszystko rozszerza Object;
  • c rozszerza Object, jak wszystko inne w TypeScript, ale nie dodaje członków. Ponieważ zgodność typów w TypeScript opiera się na podtypach strukturalnych, a nie podtypach nominalnych, c kończy się tak samo jak b, ponieważ mają ten sam interfejs: interfejs Object.

I własnie dlatego

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

i dlaczego

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

Więc Objecti {}są odpowiednikami w TypeScript.

Jeśli zadeklarujesz takie funkcje

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

z zamiarem zaakceptowania czegokolwiek dla parametrów (może będziesz sprawdzać typy w czasie wykonywania, aby zdecydować, co z tym zrobić), pamiętaj, że

  • wewnątrz fa kompilator pozwoli ci robić, co chcesz z param ;
  • wewnątrz fb kompilator pozwala tylko odwoływać się do członków Object .

Warto jednak zauważyć, że jeśli param ma akceptować wiele znanych typów, lepszym podejściem jest zadeklarowanie go za pomocą typów unii, jak w

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

Oczywiście nadal obowiązują reguły dziedziczenia OO, więc jeśli chcesz akceptować instancje klas pochodnych i traktować je na podstawie ich podstawowego typu, jak w

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..

typ podstawowy to sposób, aby to zrobić, a nie żaden . Ale to jest OO, poza zakresem, chciałem tylko wyjaśnić, że każdy powinien być używany tylko wtedy, gdy nie wiesz, co nadchodzi, a do wszystkiego innego powinieneś adnotować właściwy typ.

AKTUALIZACJA:

Maszynopis 2.2 dodaje się objecttyp, który określa, że wartość jest non-prymitywne: (czyli nie jest to number, string, boolean, symbol, undefined, lub null).

Rozważ funkcje zdefiniowane jako:

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

xbędą mieć te same dostępne właściwości we wszystkich tych funkcjach, ale jest to błąd typu wywoływany dza pomocą operacji podstawowej:

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

2
Czy ktoś wie, dlaczego zdecydował się dodać, {}jeśli już miał Object? (lub odwrotnie, w zależności od tego, co nastąpi wcześniej) Musi być jakaś niewielka różnica, prawda?
CletusW,

4
{}jest normalnym sposobem definiowania (wbudowanych) interfejsów, tyle że w tym przypadku definiujesz interfejs bez elementów. Niewielka różnica została dobrze wyjaśniona w odpowiedzi: „ {}rozszerza się Object, jak wszystko inne w TypeScript”.
DanielM

7
Chcę obniżyć głosowanie na linię Więc w zasadzie, jeśli nie znasz typu, przejdź anydo sprawdzania typu w czasie wykonywania. Nie używać any, zamiast korzystać z unii z typów jest sprawdzana przed: TypeA|InterfaceB|string. Jeśli masz również domyślną sprawę do nieznanego typu, albo dodać {}lub Objectdo unii.
ILMTitan

Dokumenty maszynowe są czasem mylące, na przykład 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:sprawiły, że pomyślałem, że nawet dzwonienie toStringjest niedozwolone, podczas gdy w rzeczywistości myślę, że chcieli powiedzieć exist at runtimepo przeczytaniu odpowiedzi.
Olga

24

any jest czymś specyficznym dla TypeScript, co dość dobrze wyjaśnia odpowiedź Alexa.

Objectodnosi się do objecttypu JavaScript . Powszechnie stosowane jako {}lub czasami new Object. Większość rzeczy w javascript jest zgodnych z typem danych obiektu, ponieważ dziedziczą po nim. Ale anyjest specyficzny dla TypeScript i kompatybilny ze wszystkim w obu kierunkach (nie na podstawie dziedziczenia). np .:

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
Twoja odpowiedź jest dość niejasne i miksy Objecti objectktóre są różne typy w maszynopisie.
m93a

@ m93a: Czy możesz rozwinąć różnicę między TS Objecti objectTS?
Alexander Abakumov

4
Jest to prawdopodobnie najlepsze źródło do poznania różnicy. Najważniejsze jest to, że objectjest typem wszystkiego, co nie jest prymitywne, podczas gdy Objectjest interfejsem, który zawiera typowe rzeczy takie jak toStringi takie. Liczba 42byłaby, Objectale nie była object.
m93a

20

W przeciwieństwie do .NET, gdzie wszystkie typy pochodzą od „obiektu”, w TypeScript wszystkie typy pochodzą od „dowolnego”. Chciałem tylko dodać to porównanie, ponieważ myślę, że będzie to powszechne, ponieważ więcej programistów .NET wypróbuje TypeScript.


16

Obiekt wydaje się być bardziej szczegółową deklaracją niż jakakolwiek inna. Ze specyfikacji TypeScript (sekcja 3):

Wszystkie typy w TypeScript są podtypami jednego górnego typu o nazwie Dowolny typ. Dowolne słowo kluczowe odnosi się do tego typu. Dowolny typ to jeden typ, który może reprezentować dowolną wartość JavaScript bez ograniczeń. Wszystkie pozostałe typy są klasyfikowane jako typy pierwotne, typy obiektów lub parametry typów. Te typy wprowadzają różne statyczne ograniczenia ich wartości.

Również:

Dowolny typ służy do reprezentowania dowolnej wartości JavaScript. Wartość typu Any obsługuje te same operacje, co wartość w JavaScript, a dla operacji na dowolnych wartościach przeprowadzane jest sprawdzanie minimalnego typu statycznego. W szczególności właściwości dowolnej nazwy można uzyskać poprzez Dowolną wartość, a Dowolne wartości można wywoływać jako funkcje lub konstruktory z dowolną listą argumentów.

Obiekty nie zapewniają takiej samej elastyczności.

Na przykład:

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

Dodanie do odpowiedzi Alexa i uproszczenie jej:

Przedmioty są bardziej surowe w użyciu, a tym samym dają programiście więcej czasu na „ocenę” mocy, a zatem w wielu przypadkach zapewniają więcej „możliwości sprawdzania” i mogą zapobiegać wyciekom, podczas gdy każdy jest bardziej ogólnym terminem i dużo kompilacji kontrole czasu mogą zatem zostać zignorowane.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.