typescript generics i default type

0

Elo nastepne pytanko dotyczace typescript-a.

https://paste.ofcode.org/rAEvdSUVp5hyfyC5ShNvaY

Czy ktos z was wie dlaczego default type dla generic T nie dziala i sie pluje po prostu mnie to denerwuje ze wtedy IDE (Vs code) mi zle podpowiada i do tego angular cli rzuca bledami przy "kompilacji" i nie chce ich tlumic.

Angular 7.2.x i typescript 3.2.4

P.S mam nadzieje ze przyklad jest jasny

0

W dalszym ciągu możesz stworzyć klasę AbstractClass, która nie będzie dziedziczyła z B:

class Foo extends AbstractClass<C> {
    
}

W jaki sposób chciałbyś w tej sytuacji uzyskać dostęp do this.data.b?

0

No wlasnie chodzi mi o to ze moze to byc jakikolwiek obiekt ktory dziedziczy po Base.
po prostu chodzi mi o to ze mam klase abstrakcyjna ktora ma prop data typu {}, ten prop data zaleznie od typy generycznego bedzie mial rozne pola (reszta metod, properties itp.. jest taka sam) ale moze sie tylko zmiescic "tresc" tego co jest w data a ja w ide chce po prostu miec podpowiedz ze jesli bede mial klase

abstract class Animal<T> {
  data: T;
}

Bird<BirdData> extends Animal {
  data: BirdData // wtedy data bedzie interfejsem BirdData
}

Dog<DogData> extends Animal {}

Nie wiem po prostu jak wymusic zmiane interfejsu w IDE jesli klasa ktora dziedziczy po Animal bedzie po prostu jako generics podawala inny interfejs.

Czyli w bazowej data bedzie zawsze tym samym typem czyli {} ale za pomoca interfejsu mam podpowiedzi co data ma w sobie, inna klasa moglaby po prostu chciec zmienic to co data ma w srodku nie wiem czy wytlumaczylem lopatologicznie :D

P.S przyklad z Animal jest troche taki wymuszony

P.S2 robie aplikacje gdzie po prostu mam rozne virtual machines i zaleznie od tego czy jest to windows/linux lub android data ma inne dane w srodku ale reszta jest zawsze taka sama, moglbym dac data: any ale wtedy w zadnym komponencie nie bede mail zadnej podpowiedzi

0

Niestety nie rozumiem o co Ci chodzi.

Robiąc coś takiego:

class Bird extends Animal<BirdData> {

}

const bird = new Bird();

... IDE powinno Ci podpowiedzieć, że bird.data jest typu BirdData.

0

No wlasnie o to mi chodzi ale tak sie nie dzieje, tzn w klasach ktory dziedzicza po Animal jest ok ale w klasie abstrakcyjnej placze i rzuca mi bledami przy transpilacji


export interface BaseVm {
  id: number;
  name: string;
  type: string;
}


export interface Vm extends BaseVm {
  moid: string;
  power_state: 'poweredOn' | 'poweredOff';
  network_interfaces: Array<{[key: number]: any}>;
  snapshot?: {[key: string]: any};
}

export abstract class AbstractVm<T extends BaseVm = Vm> implements OnInit, OnDestroy {
  powerOn(): void {
    this.data.moid // i tutaj placze
  }
}

I tak jakby default type dla generic T czyli Vm nie bylby brany pod uwage

0

Typ domyślny nie jest brany pod uwagę, bo może zostać zmieniony przez klasy potomne (patrz: przykład niżej) - najważniejszym ograniczeniem jest T extends BaseVm, a Twoje BaseVm nie zawiera pola moid.

export interface FooVm extends BaseVm {
}

export class MyVm extends AbstractVm<FooVm> {
  // czym powinno być this.data.moid?
}

W ogóle na wydaje mi się, że mamy do czynienia z problemem X/Y - dlaczego próbujesz wykorzystać tutaj typy generyczne?

0
Patryk27 napisał(a):

Typ domyślny nie jest brany pod uwagę, bo może zostać zmieniony przez klasy potomne (patrz: przykład niżej) - najważniejszym ograniczeniem jest T extends BaseVm, a Twoje BaseVm nie zawiera pola moid.

export interface FooVm extends BaseVm {
}

export class MyVm extends AbstractVm<FooVm> {
  // czym powinno być this.data.moid?
}

W ogóle na wydaje mi się, że mamy do czynienia z problemem X/Y - dlaczego próbujesz wykorzystać tutaj typy generyczne?

Na koniec zrobilem maly hack czyli do interfejsu BaseVm dodalem [x: string]: any; // hacky but works czyli wtedy w klasie abstrakcyjnej nie pluje sie.

Bo jakos nie przyszlo mi nic innego do glowy a typy generyczne sa wlasnie ok jesli chcesz sobie tez rzytowac np return type jakiejs metody i w moim przypadku tez sie wydawaly ok tym bardziej ze nie sa to typy genereczne strict jak z C# czy innych a sluza bardziej do tego zeby sie przyjaznie pracowalo z IDE.

Masz jakas inna propozycje jak to zrobic ?

1

Na koniec zrobilem maly hack (>..)

To nie jest "mały hack" - to jest całkowite zaprzeczenie idei wykorzystywania TypeScripta w pierwszym miejscu.

typy generyczne sa wlasnie ok jesli chcesz sobie tez rzytowac np return type jakiejs metody

Huh? Co to znaczy?

Masz jakas inna propozycje jak to zrobic ?

Zadałem pytanie, na które nie uzyskałem póki co odpowiedzi: dlaczego chcesz wykorzystać typy generyczne tutaj? Co one Ci dają?

0

To ze zaprzecza to inna inkoszcz, chodzi o to ze ma mi podpowiadac w IDE i wlasnie za pomoca generics daje mi to co chce nie znalazlem innego rozwiazania a na pewno nie bede pisal za kazdym razem w klasie abstrakcyjnej/podrzednej

(this.data as MojInterfejs).moid

Zeby miec podpowiedzi.

Patryk27 napisał(a):

typy generyczne sa wlasnie ok jesli chcesz sobie tez rzytowac np return type jakiejs metody

Huh? Co to znaczy?

To znaczy np to:

  get(id: number): Observable<TypedResponse> {
    return this._http.post<TypedResponse>(`url`, { id });
  }
1

Naprawdę chciałbym pomóc, lecz najzwyczajniej nie jestem pojąć tego, co robisz i dlaczego akurat w taki sposób - dodatkowo:

  1. Nie wytłumaczyłeś dlaczego potrzebujesz wykorzystać tutaj akurat typy generyczne.
  2. Zignorowałeś obydwa moje kontrprzykłady pokazujące dlaczego Twój hack nie ma sensu i tłumaczące powód, dla którego TS ma całkowitą rację nie pozwalając na taką konstrukcję.
0

@marcio: @Patryk27 dal Ci wyczerpujaca odpowiedz, ktora w zupelnosci powinna Ci wystarczyc

Jezeli tak nie jest, to jest to typowy https://en.wikipedia.org/wiki/XY_problem

Opisz co chcesz osiagnac, a nie jak to chcesz osiagnac

0

Dobra nvm przeciez napisalem co chce osiagnac i dodalem przykald sorry nie musicie na sile zawsze odslylac do linkow mozna tez napisac sorry nie wiem jak pomoc i tyle a nie na sile komus wmawiac ze zle opisal problem.

Nie wytłumaczyłeś dlaczego potrzebujesz wykorzystać tutaj akurat typy generyczne.

Napisalem w poscie wyzej wystarczy przeczytac

Widocznie default type jest brany pod uwaga tylko w klasach pochodnich nie w klasie abstrakcyjnej i stad moj problem.

2

Z mojego pobieżnej analizy (bo nie znam się na TypeScripcie) wynika iż typy domyślne służą tylko i wyłącznie do skracania kodu w typowym przypadku, tzn mając klasę class Abc<T = Xyz> mogę napisać new Abc i będzie to oznaczało new Abc<Xyz>. Semantycznie poprawnym będzie opisanie obsługi parametrów domyślnych jako dwufazowej kompilacji:

  • faza 1: argumenty domyślne są wstawiane wszędzie tam gdzie nie ma jawnych argumentów
  • faza 2: dalsza kompilacja przebiega tak, jakby argumentów domyślnych nie było

To podobnie jak z normalnymi parametrami domyślnymi. Kompilator nie może zamienić:

int dodaj(int a = 5, int b = 8) {
  return a + b;
}

na:

int dodaj(int a = 5, int b = 8) {
  return 5 + 8;
}

z oczywistych względów i te względy są analogiczne do rachunku na typach.

0

okej czyli po prostu dajac default type powiedzmy ze potomne klasy sa ok (nie ustawiajac dla nich typu beda braly ten ustawiony jako default type)
czy jest jakas mozliwosc zeby klasa abstrakcyjna ktora wlasnie ma ten default type robila lookup po propsach ktore sa wlasnie w default type interface lub bedzie to tylko dzialalo dla klas potomnych? (tak to dziala)

0

Ten default type możesz w dowolnej chwili (np. w trakcie dziedziczenia) zmienić, stąd nie niesie on żadnej praktycznej wartości dla statycznej analizy kodu (i dlatego też jest przez TS ignorowany) - dlaczego nie wrzucisz wymaganych pól do bazowego interfejsu, skoro i tak są przez Ciebie wymagane wszędzie?

0

default type jest brane pod uwagę, gdy brakuje wymaganej parametryzacji. W kodzie AbstractVm<T extends BaseVm = Vm> T jest ograniczone z góry przez BaseVm które jest podane wprost, a Vm nie ma w definicji tej klasy (AbstractVm) wpływu na T. Typ domyślny Vm jest brany, gdy w danym miejscu nie skonkretyzujesz T, a powinieneś czyli wtedy gdy napiszesz samo AbstractVm podczas, gdy powinieneś AbstractVm<CośKonkretnego>.

Podaj przykłady na to "branie pod uwagę" i "nie branie pod uwagę" to ci rozjaśnię co się skąd bierze.

PS:
Powtarzam jeszcze raz, że typ domyślny jest głównie po to, by skrócić kod, a nie by dodawać nowe gwarancje dotyczące typów. Dorzucając typ domyślny Klasa<T = MojeT> możesz wszelakie deklaracje typu Klasa<MojeT> zamienić na Klasa i tyle. Nie zmieni to w żaden sposób typów. Deklaracje typu Klasa<InneT> muszą zostać tak jak są.

1 użytkowników online, w tym zalogowanych: 0, gości: 1