microsoft / microsoft/TypeScript

Suggestion: Allow local types to be declared in interfaces

Ouverte
#9,889 12 commentaires 14 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Awaiting More Feedback Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

I have something like this:

export interface Reducer<State, Types extends Action<string, any>> {

    add<TypeName extends string, Payload>(action: {
        type: TypeName,
        reduce: (state: State, action: Payload) => State
    }): Reducer<State, Types | Action<TypeName, Payload>>;

    readonly cursorType: Cursor<State, Types>;
}

The details aren't that important except to illustrate that a Reducer is immutable, and has an add method that returns another Reducer, but see that the return type has something extra "unioned" into it. By repeated chained calls to add I can build up a big nasty old type that would be ugly to have fully declare by hand. Fortunately type inference takes care of building the type for me, which is great.

Then elsewhere in my code I want to be able to declare something called a "cursor", which needs to have a type that corresponds to the reducer's type. The cursor could be a field in a class so I need to be able to refer to the type so I can declare such a field.

So I want to provide a simple way to declare a const of the type "correct kind of cursor for a given reducer", leveraging the work that the TS compiler already did for me with its type inference.

My slightly hacky approach, as shown above, is to declare a readonly field cursorType. The value of this is at runtime is junk and should not be used! So I need a "here be dragons" comment on it. Its only purpose is to be prefixed with typeof, e.g.:

const R = getReducerSomehow();

class Test {
    constructor(public readonly myCursor: typeof R.cursorType) { }
}

To fill in the cursorType field of a Reducer I have to do this filth:

newReducer.cursorType = {} as Cursor<State, Types>;

So cursorType really should never be used as a value. It doesn't even need to exist as a value. It will cause a runtime error if anyone tries to used it as a cursor. Ugh. But how else can I make this elaborately computed type available conveniently?

I'm wondering if TS could allow:

export interface Reducer<State, Types extends Action<string, any>> {

    add<TypeName extends string, Payload>(action: {
        type: TypeName,
        reduce: (state: State, action: Payload) => State
    }): Reducer<State, Types | Action<TypeName, Payload>>;

    // not currently possible:
    type CursorType = Cursor<State, Types>;
}

i.e. a type alias can be added to an interface. So now my implementation of Reducer no longer has to do anything. No nasty dummy runtime variable hack required.

And my usage example becomes:

const R = getReducerSomehow();

class Test {
    constructor(public readonly myCursor: R.CursorType) { }
}

That is, CursorType is a type that can be referred to as if it was a member of an instance. Similar I guess to:

namespace N {
    export type S = string;
}

const s: N.S = "hi";

In which N is an object at runtime and yet can also be used to find the type S.

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par les exemples de Reducer, Cursor et de CursorType proposés dans l’issue, puis étudiez comment TypeScript représente les membres d’interface et les alias de type. Déterminez les points d’entrée du compilateur et les tests nécessaires pour les alias de type qualifiés par instance ; le travail est terminé lorsque la syntaxe proposée est vérifiée par le système de types sans champ à l’exécution, tout en préservant le comportement existant des interfaces.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.