Typescript: Prise en charge des propriétés ES Rest/Spread proposées

Créé le 21 févr. 2015  ·  96Commentaires  ·  Source: microsoft/TypeScript

proposition es7 : https://github.com/sebmarkbage/ecmascript-rest-spread

Propriétés de propagation

Dactylographie

À mon avis, le but de cette méthode est de pouvoir dupliquer un objet et de changer certains accessoires, donc je pense qu'il est particulièrement important dans ce cas de ne pas vérifier la déclaration de propriété en double :

var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3, y: 4}; // not an error

J'ai un algorithme de vérification de type très naïf pour une fonctionnalité similaire ( JSXSpreadAttribute ) dans mon petit fork jsx-typescript : je copie juste les propriétés de l'_objet de propagation_ dans la table des propriétés lorsque je rencontre un objet de propagation , et remplacez ces propriétés si je rencontre une déclaration avec un nom similaire.

Émettant

jstransform utilise Object.assign , babel introduit une cale :

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

Nous pourrions soit forcer la présence de la fonction assign sur l'interface ObjectConstructor , soit fournir une fonction similaire (avec un nom différent).

Je pense que la solution optimale serait de ne pas émettre de helper dans la cible es6 (ou si Object.assign est défini), et d'émettre une fonction helper pour es5 , es3 .

var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3};

/// ES6 emit
var obj = {x: 1, y: 2};
var obj1= Object.assign({}, obj, { z: 3 });

//ES3 emit
var __assign = function (target) { 
    for (var i = 1; i < arguments.length; i++) { 
        var source = arguments[i]; 
        for (var key in source) { 
            if (Object.prototype.hasOwnProperty.call(source, key)) { 
                target[key] = source[key];
            } 
        } 
    } 
    return target; 
};

var obj = {x: 1, y: 2};
var obj1= __assign({}, obj, { z: 3 });

Propriétés de repos

Dactylographie

Pour un objet simple, le nouveau type est un sous-type de l'assignation qui ne contient pas de propriétés capturées avant les autres propriétés :

var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
obj1// {x: number; y:number};

Si l'affectation de déstructuration a une déclaration d'index, le résultat a également une déclaration d'index similaire :

var obj: { [string: string]: string };
var {[excludedId], ...obj1} = obj;
obj1// { [string: string]: string };

les déclarations de nouveaux/appels ne sont évidemment pas capturées :

var obj: { (): void; property: string};
var { ...obj1} = obj;
obj1// { property: string };

Émettant

Il n'est pas possible d'émettre _rest properties_ sans fonction d'assistance, celle-ci vient de babel :

var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
var __objectWithoutProperties = function(obj, keys) {
    var target = {};
    for (var i in obj) {
        if (keys.indexOf(i) >= 0) continue;
        if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
        target[i] = obj[i];
    }
    return target;
};

var obj = {x:1, y: 1, z: 1};
var z = obj.z;
var obj1 = __objectWithoutProperties(obj, ["z"]);

_Edit : ajout de quelques petits exemples de saisie/émission_

Committed ES Next Fixed Suggestion

Commentaire le plus utile

Je ne sais pas comment nous allons finalement l'expédier, mais j'ai commencé à travailler sur le repos/spread dans les littéraux d'objet et la déstructuration . Pour le moment, le plan est d'utiliser notre polyfill __assign pour l'émission.

Tous les 96 commentaires

Nous aurions probablement besoin de quelques exemples de la façon dont cela pourrait être émis de manière plausible dans le niveau inférieur (si cela est dans la portée).

@RyanCavanaugh , j'ai ajouté un petit exemple d'émission et une idée de frappe.
J'aimerais travailler dessus car de toute façon c'est plus ou moins une fonctionnalité jsx et je vais devoir l'ajouter à mon fork, mais si c'est ajouté au noyau tapuscrit c'est mieux ^^.

J'ai récemment découvert cette fonctionnalité dans ES7 via cet article . Je dois dire que c'est très pratique !

J'adorerais voir cela dans TypeScript !

Des mises à jour à ce sujet ? J'adorerais voir cela dans 1.6 car cela serait très pratique lors de l'utilisation avec React :smile:

@prabirshrestha pour mémoire, nous avons actuellement l'opérateur de propagation de propriété pour JSX sur master .

@DanielRosenwasser Pourriez-vous développer ? Cela signifie-t-il que cela fonctionne sur le maître avec l'indicateur --jsx ? Cela inclut-il les propriétés de repos ou simplement les propriétés de propagation ?

Désolé @mnpenner et @prabirshrestha , oui, je voulais dire sur master . @RyanCavanaugh en sait plus que moi à ce sujet, mais je pense qu'il s'agit simplement de diffuser des propriétés.

JSX prend en charge les _attributs_ de propagation, par exemple <TagName {...spreadedExpr} /> . Rien à voir avec l'opérateur de propagation ES6 autre que de partager le même jeton et d'avoir une sémantique à peu près équivalente.

Je suis très intéressé à la fois par Redux et React, la manipulation en état est beaucoup plus facile avec cela. J'adorerais voir cela mis en œuvre.

Rest/Spread est maintenant approuvé pour l'étape 2 https://github.com/tc39/tc39-notes/blob/master/es7/2015-07/july-30.md

Nous voulons attendre que la proposition atteigne l'étape 3 avant d'aborder cette question.

C'est très utile pour réagir et redux, s'il vous plaît implémentez-le dès que possible, s'il vous plaît :-)

Voici un module d'aide que j'ai utilisé pour contourner ce problème. Ce n'est pas idéal car vous devez spécifier toutes les touches deux fois, une fois du côté gauche et une fois sous forme de chaînes du côté droit, mais je ne peux pas penser à une meilleure façon de le faire. Tout commentaire est le bienvenu, je suis sûr qu'il y a un comportement de bord que j'ai manqué !

https://gist.github.com/tomduncalf/fbae862b123445c117cb

Est-ce quelque chose pour lequel vous accepteriez un patch ? (à fusionner une fois atteint le stade 3). Et si oui, avez-vous des conseils pour commencer à apporter des modifications pour le prendre en charge ?

Il s'agit de la dernière fonctionnalité ES7+ que mon équipe utilise beaucoup et qui nous empêche de passer au tapuscrit ; J'adorerais certainement avoir à le faire plus tôt, si possible.

Nous envisagerions un PR ici. Une remarque cependant, le câblage du système de type pour cette fonctionnalité n'est pas une tâche simple. Si vous êtes intéressé à lire cela, je le garderais incrémentiel, et commencerais par analyser puis émettre puis taper la vérification. @sandersn devrait pouvoir vous aider si vous avez des questions.

Juste une note pour ceux qui souhaitent l'utiliser avec Redux. Je suis d'accord que la notation est pratique. Mais en fait, je me débrouille très bien sans cela en tirant parti de la bibliothèque updeep . J'ai créé quelques dactylographies de base pour cela et cela fonctionne plutôt bien. J'ai même une bibliothèque simple qui implémente un magasin et des actions basés sur updeep . Si cela intéresse quelqu'un, contactez-moi.

Dans tous les cas, :+1: pour les opérateurs d'étalement dans TS. :le sourire:

@xogeny Je serais très intéressé à jeter un œil à cette bibliothèque. Merci

@ cur3n4 J'ai un référentiel où j'ai joué avec ces idées. Cela change un peu (puisque tout est encore en évolution). J'utilisais un module spécial qui utilisait initialement updeep et cette fonctionnalité est toujours dans la bibliothèque . Mais j'ai arrêté de l'utiliser car j'avais du mal à maintenir les contraintes de type nécessaires. Je suppose que si Typescript avait quelque chose du genre des contraintes de type génériques super de updeep (et plusieurs autres bibliothèques, comme lodash ou ramda ) pourrait être fait beaucoup plus de type sûr.

Mais ne vous méprenez pas, je pense toujours qu'un opérateur de propagation serait vraiment utile. Cela vous permettrait en fait d'exprimer et de faire des choses en toute sécurité et laconiquement dans le langage que je ne vois pas comment faire avec le système de types actuel (_c'est-à-dire_ vous permettant de décrire les bonnes contraintes de type sur les bibliothèques externes). Pour le moment, je sacrifie la concision pour la sécurité (alors que l'approche updeep sacrifie la sécurité pour la concision).

Après avoir utilisé Babel au cours des derniers mois, j'ai converti mon projet en TS et j'ai dû refaire tout cela. J'adorerais voir cela mis en œuvre!

:+1:

J'adorerais voir ça.

+1

doit avoir une fonctionnalité, s'il vous plaît implémenter

+1

+1 syntaxe beaucoup plus agréable que Object.assign + prise en charge de JSX

+1 indispensable pour le développement de réaction pour la transmission d'accessoires ( var { checked, ...other } = this.props; . voir la documentation de réaction

c'est un must have pour réagir développement

Soyons honnêtes, c'est une commodité, pas un must. La proposition est à l'étape 2 avec TC39. L'équipe TypeScript a clairement indiqué qu'elle ne voulait pas envisager de mettre en œuvre des éléments qui ne proviennent pas de TypeScript avant d'être à l'étape 3. La place pour "+1" est avec TC39.

@kitsonk - vous ne pouvez pas vous attendre à une bonne adoption lorsque des frameworks comme React / etc appellent spécifiquement ce type de choses dans leurs documents. Les gens commenceront à utiliser Typescript, verront tous ces problèmes et retourneront à Babel. C'est ce que j'ai fait.

Eh bien, je pense que nous parlons d'un sujet plus large. Aucun fournisseur de navigateur n'implémentera quelque chose qui n'est pas à l'étape 3 (à moins qu'il ne l'aime personnellement). Le TC39 a essayé de donner un certain niveau d'organisation à sa partie du Web. TypeScript a été mordu, énormément, en sautant le pistolet avant (modules, et regardez le chaos que cela a causé depuis). Je respecte le fait qu'ils essaient au moins d'orienter et de structurer ce qu'ils sont prêts à mettre en œuvre et à quel moment. Existe-t-il une autre suggestion sur la norme à utiliser ? Je ne pense pas que « parce que le framework X le mentionne dans sa documentation » serait un bon choix.

les frameworks comme react / etc appellent spécifiquement ces types de choses dans leurs docs

Ce qu'ils marquent uniquement comme une proposition, puis vous explique comment sauter à travers les cerceaux pour configurer Babel 6 pour l'utiliser. Je préférerais blâmer les frameworks de dépendre de technologies syntaxiques qui n'en sont qu'à un projet de spécification. Personnellement, nous, à Dojo, avons été brûlés par Object.observe et je suis de nouveau réticent à essayer de dépendre des technologies avant qu'elles n'atteignent l'étape 3 de Dojo.

Le chemin particulier va bien au-delà de la simple prise en charge de la transformation de la syntaxe lors de l'émission pour TypeScript. Il y a toutes les inférences de type qui doivent suivre. J'ai regardé le brouillon pour comprendre, mais où vont les symboles ? Où vont les propriétés non dénombrables ? Je suppose que dans les deux cas, ils disparaissent simplement dans l'éther, mais il y aura toutes sortes de divisions et de fusions de types qui devront se dérouler en arrière-plan pour cela, donc je peux tout à fait comprendre que l'équipe TypeScript dise " ok, attendons là-dessus jusqu'à ce que le TC39 ait vraiment donné un coup de pied aux pneus là-dessus".

Dans l'ensemble, je pense que TS est assez bien présenté aujourd'hui. Il fut un temps (environ 1,4 ~ 1,5 je pense) où j'étais frustré par le manque de certaines fonctionnalités ES2015, mais à ce jour, TS a assez bien rattrapé le standard.

Bien sûr, il y a parfois une envie de fonctionnalité par rapport à d'autres langues. Par exemple, Babel propose à peu près n'importe quelle proposition JS, y compris des éléments "expérimentaux". Personnellement, j'attends avec impatience ce problème ainsi que l'opérateur de liaison de fonction.

Mais en même temps, nous devons reconnaître que l'équipe TS prend la compatibilité beaucoup plus au sérieux que Babel. Ils ne veulent pas changer la sémantique de votre code entre les versions, ou simplement supprimer une fonctionnalité, ce que fait Babel. Pour certains projets (d'entreprise ?) c'est important.

Je peux également comprendre que MS ne veuille pas investir beaucoup de ressources dans des fonctionnalités qui pourraient être abandonnées, le fiasco Object.observe me vient à l'esprit. En fait, ils ont dit qu'ils envisageraient un PR sur celui-ci par exemple : wink:.

Dans le passé, certaines fonctionnalités ont été ajoutées tôt derrière un commutateur de compilateur expérimental (par exemple, async), ce qui signifiait que vous deviez vous inscrire et reconnaître que la fonctionnalité pouvait changer ou être supprimée dans les futures versions. Peut-être que cela pourrait être refait pour les demandes les plus populaires ?

Juste une note rapide ici. Nous avons été plutôt lents à adopter les fonctionnalités ES proposées pour l'étape 0-1, principalement en raison de problèmes de compatibilité descendante. Nous suivons de près les discussions lors des réunions du TC39 et participons directement aux réunions ou aux préparations de propositions avant les réunions ; et lorsque nous insérons une fonctionnalité, nous aimerions savoir ce que cela signifie pour les utilisateurs qui en dépendent.
Si vous regardez la documentation du processus TC39, une fonctionnalité à l'étape 1 peut s'attendre à des changements « majeurs » après l'acceptation. C'était le cas pour les classes, les modules, les itérateurs et presque toutes les fonctionnalités ES6 non triviales.
En mettant mon chapeau d'utilisateur, les modifications de rupture de syntaxe peuvent être mécaniques, tandis que les modifications de rupture de sémantique peuvent être extrêmement difficiles à détecter et à corriger ; cela peut représenter un coût énorme pour les équipes utilisant l'une de ces fonctionnalités et/ou un blocage pour l'adoption de versions plus récentes des outils. et nous aimerions minimiser cela lorsque cela est possible. C'est pourquoi nous avons adopté une politique pour activer les fonctionnalités par défaut lorsqu'elles atteignent le stade 3, et sous un drapeau expérimental avant cela (par exemple les décorateurs).
Cela dit, la propagation et le repos de la propriété d'objet sont sur notre feuille de route et nous prévoyons de les aborder dans une future version.

Peut-être vaut-il la peine d'ajouter à la capacité du compilateur d'injecter des extensions tierces, comme cela se fait dans babel ?

Autre réflexion : qu'en est-il du support du prétraitement des sources tapuscrites (avec Babel) ?

Si nous pouvons faire en sorte que Babel (ou toute autre bibliothèque) étende les objets répartis en appels Object.assign , cela pourrait fonctionner assez bien ? Il serait, espérons-le, généralisable à d'autres fonctionnalités expérimentales implémentées dans Babel également.

@kitsonk - sujet plus large absolument, dang souhaite que github ait de meilleures discussions ;). Je ne suis pas du tout d'accord avec toi :

. TypeScript a été mordu, énormément, en sautant le pistolet avant (modules, et regardez le chaos que cela a causé depuis).

Ils sont partis et ont fait leur propre implémentation en reflétant .NET sans rien utiliser de la communauté, c'est de leur faute.

mettre des conseils et une structure autour de ce qu'ils sont prêts à mettre en œuvre et quand

ils implémentent des décorateurs ( étape 1 ), des propriétés de classe ( étape 1 ), etc.

Je ne pense pas que « parce que le framework X le mentionne dans sa documentation » serait un bon choix.

tu plaisante pas vrai? réagir est le cadre le plus populaire et a une projection pour le rester pendant un certain temps maintenant. ne pas soutenir cela va/a vraiment nui à l'adoption.

Je pense que TypeScript a beaucoup de retard à rattraper avec Babel et il y a beaucoup de défis tels que : vraiment difficile de commencer à l'utiliser avec une application existante, migrer de babel à dactylographié pour A2 est un CAUCHEMAR !, manque de plugins découplés rend le travail avec Node extrêmement difficile.

tu plaisante pas vrai? réagir est le cadre le plus populaire et a une projection pour le rester pendant un certain temps maintenant. ne pas soutenir cela va/a vraiment nui à l'adoption.

J'ai beaucoup de respect pour React, mais je ne plaisante pas. Ce n'est pas le seul jeu en ville et il est certainement sur une grande courbe de battage médiatique. Il y a 6 mois c'était React + Flux, maintenant React + Redux est la saveur du jour. Il y a un an, Angular et Polymer. Il y a deux ans, c'était Backbone et Ember. Il y a six ans c'était Dojo, MooTools, jQuery, gwt, ExtJS, etc...

ne commencez pas les guerres de framework ici :exclamation:
{..., } syntaxe de

Ils sont partis et ont fait leur propre implémentation en reflétant .NET sans rien utiliser de la communauté, c'est de leur faute.

@a impurel De quoi

+1 pour que cela soit inclus dans le nœud dactylographié js le supporte expérimentalement

let typescript = { ...typescript, object_spread } ; // Oui s'il vous plaît.

Dommage qu'il n'y ait aucun mouvement à ce sujet, j'espère vraiment que cela atteindra bientôt l'étape 3. Va tuer la mise en évidence des erreurs de syntaxe dans VSCode si possible

Je me demande si la salsa change quelque chose au jeu ?

Je comprends que TS ne souhaite pas implémenter des fonctionnalités instables à l'avance : ressources limitées, nous protégeant les utilisateurs d'éventuels changements de rupture, etc.

Mais maintenant que Salsa est le moteur JS par défaut de VS Code, la pression pour une nouvelle syntaxe JS (au moins juste la syntaxe, pas la saisie TS complète) va augmenter. Surtout vu la popularité de Babel.

La Salsa va-t-elle pouvoir accepter une syntaxe plus large plus rapidement que TS ?

+1

Est-ce que ce sera en 2.1 plutôt qu'en 2.0 ? :cri:
https://github.com/Microsoft/TypeScript/wiki/Roadmap#21

Compte tenu de la taille de la version 2.0, je ne suis pas trop surpris.

Nous essayons de garder les versions à 6-8 semaines d'intervalle ; de sorte que cela limite ce qui peut y entrer. Nous effectuons actuellement une refactorisation des émetteurs et devrions pouvoir ajouter cette fonctionnalité une fois celle-ci terminée.

Alors est-ce que c'est réglé ?

... fonction d'assistance autonome pour les attributs de propagation
https://github.com/Microsoft/TypeScript/releases/tag/v1.8.10

Étant donné que je reçois toujours le « Modèle de restructuration de la propriété attendu »

Pas exactement. Ce correctif concerne spécifiquement les attributs de propagation JSX :

const props = { foo: "bar" };
return <SomeComponent {...props} />;

qui fonctionnait déjà, avant que React v15 ne supprime une fonction interne non documentée dont dépendait le compilateur JSX de TypeScript. Oups

La propagation d'objets est une proposition différente, avec une syntaxe certes similaire (elle a peut-être même été proposée par des ingénieurs de Facebook et inspirée de l'équivalent JSX, bien que je n'en sois pas sûr).

Donc, puisque {...props} ne fonctionne pas encore, comment utiliseriez-vous TypeScript pour obtenir quelque chose de similaire ?

Donc, puisque {...props} ne fonctionne pas encore, comment utiliseriez-vous TypeScript pour obtenir quelque chose de similaire à cela

Utilisez xtend : https://www.npmjs.com/package/xtend il a d'excellentes frappes : https://github.com/typed-typings/npm-xtend (par @blakeembrey :rose:) merci au type d'intersection

Ou n'utilisez aucune bibliothèque !

const newProps = Object.assign({} /*new object*/, props /* add all attributes of props */, {
   // add additional props
  bar: "baz"
});

C'est un peu verbeux, mais c'est natif d'ES2015, donc si vous avez déjà un polyfill pour ça, vous êtes solide.

Cet opérateur est l'une des principales raisons pour lesquelles nous avons décidé d'utiliser babel dans un projet au lieu de tapuscrit.

Change complètement le jeu pour manipuler les objets de manière immuable.

Comme alternative, y a-t-il quelque chose de prévu qui vous permette de connecter une transformation personnalisée à TSC comme vous pouvez le faire dans babel ? Peut-être même basé sur la même API, ce serait génial et résoudrait des problèmes comme celui-ci.

Comme alternative, y a-t-il quelque chose de prévu qui vous permette de connecter une transformation personnalisée à TSC comme vous pouvez le faire dans babel

@Niondir Oui. Recherchez simplement les balises [Transforms] . Ceux-ci sont nécessaires pour obtenir une transpilation async/wait/generator appropriée dans le compilateur TypeScript :rose:

Après une petite recherche, tu fais référence à ça ? https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API

Ça a l'air génial. Je ne trouve rien en rapport avec la propagation d'objets pour cette API. Ce serait peut-être un joli petit projet pour résoudre ce problème basé sur l'API du compilateur :)

@Niondir désolé de ne pas avoir fourni une meilleure aide dans mon message d'origine. Je parle de https://github.com/Microsoft/TypeScript/issues/5595 < qui permettra de brancher emit pour la syntaxe ESNext. TypeScript est un peu plus impliqué que Babel car il doit avoir une compréhension du système de type _sémantique_ de votre code, donc le travail de propagation d'objets devra probablement provenir de l'équipe TypeScript.

Avoir un émetteur basé sur un plugin rendrait cela plus facile. Oui, vous utiliseriez l'API du compilateur (ou potentiellement fork le compilateur au début jusqu'à ce qu'un système de plugin soit rendu public + pour la logique sémantique / scanner)

Cela pourrait être une question pour un autre problème, mais ne serait-il pas possible d'ajouter une option "allow-experimental" et de faire en sorte que TypeScript autorise les choses futures? Par exemple, autorisez l'opérateur de propagation et la sortie telle quelle. Je peux gérer ça avec babel après.

C'est une fonctionnalité indispensable pour certains projets sur lesquels je travaille et je ne peux pas migrer sans des éléments essentiels comme celui-ci. Ce serait génial si je pouvais.

Je ne sais pas comment nous allons finalement l'expédier, mais j'ai commencé à travailler sur le repos/spread dans les littéraux d'objet et la déstructuration . Pour le moment, le plan est d'utiliser notre polyfill __assign pour l'émission.

C'est la meilleure nouvelle que j'ai entendue au cours des 3 derniers mois !

Malheureusement, il s'avère que faire fonctionner cela avec des génériques est un _beau_ de travail. Vous devez correctement prendre en charge le code comme celui-ci :

function addId<T>(t: T): {...T, id: number} {
    return { ...t, id: 1 };
}

Comme vous pouvez le voir, addId renvoie un nouveau type de type, un type d'objet qui inclut un opérateur de propagation.

Après quelques discussions, nous avons décidé de reporter jusqu'à la 2.1 et de revoir cela. Nous devons nous concentrer sur la réalisation des fonctionnalités 2.0 dès maintenant.

Pardonnez mon ignorance... mais j'ai l'impression que addId dans ce cas peut retourner T & { id: number } ? Ou y a-t-il une bizarrerie des types d'union qui empêche cela d'être une solution optimale ?

Je pense qu'il veut dire qu'en fait T devrait être vérifié, puisque vous pouvez passer n'importe quoi à T

addId<boolean>(true);
addId<number>(5);

Babel ignore silencieusement de telles déclarations let a = { ...true } mais je pense qu'elles ne devraient pas être valides

Ce n'est pas T & { id: number } car si T a une propriété id , elle sera remplacée.

D'autre part, l'intersection, le type résultant de id serait l'intersection de T de type id et number .

Donc, ce que @sandersn dit, c'est que vous avez besoin d'un opérateur de type distinct.

Alors que nous bénéficierions certainement d'une meilleure solution de typage ici, Object.assign existe déjà et utilise naïvement les intersections comme type de sortie. Pourquoi ne pourrions-nous pas, comme mesure d'arrêt, l'opérateur de repos faisant exactement ce que fait Object.assign ?

Cela soulagerait beaucoup de préoccupations concernant la fonctionnalité manquante et cela n'apporterait pas de comportement indésirable puisque les gens utilisent déjà Object.assign place.

J'étais en fait extrêmement surpris que cela ne soit pas pris en charge.

Dès que nous obtenons cela, nous sommes de plus en plus joyeux. Fonctionnera très bien avec réagir !

Je serais heureux même si ce n'était pas tapé

@ 2426021684 Cela peut sembler raisonnable, mais considérez les implications. S'il n'est pas tapé, c'est-à-dire tapé sous la forme any , toute utilisation de la syntaxe percolera any jusqu'aux feuilles des expressions.

@aluanhaddad ce serait la même chose que Object.assign qui est la solution de contournement que tout le monde doit utiliser car ils n'ont pas le choix (voir le post JabX ci-dessus)

Veuillez envisager de mettre en œuvre la suggestion de Object.assign serait un pis-aller très utile en attendant la "bonne" implémentation. Ne laissez pas la perfection être l'ennemi du bien.

Les propriétés de repos sont extrêmement importantes avec React 15.2, comme on peut le voir ici https://facebook.github.io/react/warnings/unknown-prop.html

const divProps = Object.assign({}, props)
delete divProps.layout

est très moche, surtout si la quantité d'accessoires sur un composant est plus élevée

pour ceux qui ne peuvent plus attendre voici une solution de contournement :

function steal(result: any, data: any): any {
    for (var key in data) {
        if (value.hasOwnProperty(key)) {
            result[key] = data[key];
        }
    }
    return result;
}

export class SameAs<a> {
    constructor(public result: a) { }
    public and<b>(value: b): SameAs<a & b> {
        return new SameAs<a & b>(steal(this.result, value));
    }
}
export function sameAs<a>(value: a): SameAs<a> {
    return new SameAs(steal({}, value));
}

// example of use:

const mixture = sameAs(one).and(anotherOne).and(yetAnotherOne).result; // <-- ta-da!

Ignorez ce post, voir ci-dessous pour une meilleure mise en œuvre

Voici ce que j'ai trouvé pour une opération de déstructuration d'un mauvais codeur (dactylographié):

declare interface ObjectConstructor {
  destruct<T extends Object>(data: T, props: any): T;
  destruct<T extends Object>(data: T, ...propNames: string[]): T;
}

function destruct<T extends Object>(data: T, ...removals: string[]) {
  const rest = <T>{};

  const keys = removals.length === 1 && typeof removals[0] === 'object' ?
    Object.getOwnPropertyNames(removals[0]) :
    <string[]>removals;

  Object
    .getOwnPropertyNames(data)
    .filter(x => keys.indexOf(x) < 0)
    .forEach(x => {
      (<any>rest)[x] = (<any>data)[x];
    });

  return rest;
}

Object.destruct = destruct;

// Usage example:

const srcObj = { A: 'a', B: 'b', C: 'c' };
// destruct using an object template
const onlyC = Object.destruct(srcObj, { A: null, B: null });
// destruct using property names
const onlyA = Object.destruct(srcObj, 'B', 'C');

L'avantage évident d'utiliser une mise en page d'objet est que vous pouvez taper la mise en page et à tout le moins obtenir des conflits de type s'il vous arrive de refactoriser quoi que ce soit.

Mettre à jour (ignorez également cela, voir ci-dessous pour encore mieux)

J'ai retravaillé cela (après avoir joué avec dans un environnement réel) et j'ai proposé des fonctions beaucoup plus faciles à utiliser.

function deconstruct<TResult, TData>(
  result: TResult,
  data: TData,
  onHit: (result: TResult, data: TData, x: string) => void,
  onMiss: (result: TResult, data: TData, x: string) => void,
  propNames: string[]
  ) {

  Object
    .getOwnPropertyNames(data)
    .forEach(x => {
      if (propNames.indexOf(x) < 0) {
        if (onMiss != null) {
          onMiss(result, data, x);
        }
      }
      else {
        if (onHit != null) {
          onHit(result, data, x);
        }
      }
    });

  return result;
}

// shallow clone data and create a destructuring array of objects
// i.e., const [ myProps, rest] = destruct(obj, 'propA', 'propB');
function destruct<T>(data: T, ...propNames: string[]) {
  return deconstruct(
    [ <T>{}, <T>{} ],
    data,
    (r, d, x) => (<any>r[0])[x] = (<any>d)[x],
    (r, d, x) => (<any>r[1])[x] = (<any>d)[x],
    propNames
  );
}

// shallow clone data and create a destructuring array of properties
// i.e., const [ propA, propB, rest] = destructProps(obj, 'propA', 'propB');
function destructProps(data: any, ...propNames: string[]) {
  return deconstruct(
    [ <any>{} ],
    data,
    (r, d, x) => r.splice(r.length - 1, 0, d[x]),
    (r, d, x) => r[r.length - 1][x] = d[x],
    propNames
  );
}

// shallow clone data and remove provided props
// i.e., const excluded = omit(obj, 'excludeA', 'excludeB');
function omit<T>(data: T, ...propNames: string[]) {
  return deconstruct(
    <T>{},
    data,
    null,
    (r, d, x) => (<any>r)[x] = (<any>d)[x],
    propNames
  );
}

La saisie sur ces fonctions rend les choses beaucoup plus faciles à utiliser. Je travaille spécifiquement avec ceux-ci dans React, donc avoir une frappe forte sur mes accessoires connus est très pratique. Il existe un morceau de code supplémentaire utilisant ces fonctions qui est particulièrement pratique pour réagir :

const [ props, restProps ] = destruct(omit(this.props, 'key', 'ref'), 'id', 'text');

Dans ce cas, props est tapé comme this.props , mais ne contient aucun des accessoires destinés au transfert en aval (qui vivent maintenant dans restProps )

OMI, il n'y a pas grand-chose à gagner en publiant des solutions de contournement non sécurisées pour ce problème.

d'accord, je travaille sur une version plus typée en ce moment.

Un autre coup à ceci:

L'extension d'objet principale :

declare interface ObjectConstructor {
    rest<TData, TProps>(data: TData, propsCreator: (x: TData) => TProps, ...omits: string[]): { rest: TData, props: TProps };
}

function rest<TData, TProps>(data: TData, propsCreator: (x: TData) => TProps, ...omits: string[]) {
  const rest = <TData>{};
  const props = <TProps>propsCreator.apply(this, [ data ]);

  Object
    .getOwnPropertyNames(data)
    .filter(x => props.hasOwnProperty(x) === false && omits.indexOf(x) < 0)
    .forEach(x => {
      (<any>rest)[x] = (<any>data)[x];
    });

  return {
    rest,
    props,
  };
}

Object.rest = rest;

Une extension spécifique à React :

declare module React {
  interface Component<P, S> {
    restProps<T>(propsCreator: (x: P) => T, ...omits: string[]): { rest: P, props: T };
  }
}

function restProps<P, S, T>(propsCreator: (x: P) => T, ...omits: string[]) {
  return Object.rest((<React.Component<P, S>>this).props, propsCreator, ...omits.concat('key', 'ref'));
}

React.Component.prototype.restProps = restProps;

Quelques exemples d'utilisation :

const src = { A: 'a', B: 'b', C: 'c' };
const { rest, props } = Object.rest(src, x => {
    const props = { A, C } = x;
  return { A, C };
});

Et un exemple d'utilisation de l'extension react :

const { rest, props } = this.restProps(x => {
  const { header, footer } = x;
  return { header, footer };
});

Toutes les saisies doivent être conservées. la seule partie qui me dérange est le créateur d'accessoires car il nécessite une duplication. Je pense que je pourrais le pirater et supposer que l'objet déstructuré vit à _a mais cela semble _dangereux_...
_REMARQUE _ : _a n'est même pas un hack viable, car ce serait l'équivalent de x .

Voici un violon pour jouer avec.

Je pense que renvoyer un tableau pourrait être plus logique, car vous pouvez renommer les sorties selon vos besoins.

grattez cela, cela empêcherait d'obtenir une saisie correcte pour les accessoires.

Puisque la plupart des gens ici veulent l'utiliser avec react, pourquoi ne pas l'implémenter uniquement pour les fichiers *.tsx jusqu'à ce qu'il atteigne l'étape 3 ?

Les réducteurs Redux peuvent également être écrits sous forme de fichiers *.tsx, justeobj les instances de transtypage doivent être converties en obj en tant que type

C'est très utile non seulement pour réagir, mais dans les réducteurs redux par exemple.

Je pense que les balises et les jalons manquants à ce sujet sont un peu obsolètes. Parce que cela est commis et en cours d' élaboration (# 10727) pour tapuscrit 2.1. Donc plus besoin de débattre de la valeur de celui-ci.

ping @mhegazy

Mise à jour des balises. Je dois préciser que la raison pour laquelle cela n'a pas encore été mis en œuvre n'est pas la valeur, mais plutôt la complexité de la mise en œuvre du système de types. la transformation elle-même est plutôt triviale, c'est- {...x} dire Object.assign({}, x) . le problème est de savoir comment ces types sont prétestés et comment ils se comportent. par exemple pour un paramètre de type générique T est {...T} assignable à T , qu'en est-il de {x: number, ...T} , qu'en est-il si T a des méthodes, etc. https://github.com/Microsoft/TypeScript/issues/10727 fournit une explication plus détaillée des modifications du système de types nécessaires.

J'apprécie pleinement le fait que les augmentations du système de types requises pour un traitement idéal de cette fonctionnalité ne sont pas triviales, et c'est formidable de voir qu'elles sont abordées avec enthousiasme ! Je voudrais juste répéter que,

mettre en place la prise en charge syntaxique des spreads de propriétés + le typage naïf de Object.assign serait un pis-aller très utile en attendant la "bonne" implémentation. Ne laissez pas la perfection être l'ennemi du bien.

Il semble que la proposition ait atteint l'étape 3 : https://github.com/tc39/proposals

@ddaghan votre exemple avec tsx ne fonctionnera pas

un délai pour cette fonctionnalité ?

@ SpyMaster356 Je cache ça depuis un moment et on dirait que c'est proche. @sandersn s'en est donné à

Vous pouvez suivre ici (https://github.com/Microsoft/TypeScript/pull/12028) et ici (https://github.com/Microsoft/TypeScript/pull/11150)

Quelqu'un devrait mettre à jour la feuille de route

Il semble que l'utilisation de cette fonctionnalité permette l'affectation d'accessoires inconnus :

interface State {
  a: string;
  b: number;
}

let state: State = { a: "a", b: 0 };

state = {...state, x: "x"}; // No error

Je m'attendais à une erreur indiquant que x n'est pas une propriété connue de State . N'est-ce pas ainsi que fonctionne la fonctionnalité ?

Par exemple, ma solution de contournement actuelle avant ce PR était la suivante :

state = update(state, { x: "x" }); // Error: Property 'x' is missing in type 'State'.

function update<S extends C, C>(state: S, changes: C): S {
  return Object.assign({}, state, changes);
}

Est-il possible d'y parvenir avec la propagation/le repos de l'objet ?

Object Rest and Spread, selon la proposition ES , se comporte de manière similaire à Object.assign . la dernière mention de la propriété "gagne". aucune erreur n'est signalée. dans l'exemple que vous aviez, le type de {...state, x:"X"} est { a: string, b:number, x:string } ; et ce type est assignable à State et donc l'assignation fonctionne. cela revient à dire que let state: State = { a: "a", b:0, x: "X" }; serait également autorisé.

Mais c'est ce qui me perplexe : let state: State = { a: "a", b:0, x: "X" } donne l'erreur Object literal may only specify known properties, and 'x' does not exist in type 'State' qui est ce que je veux... pourquoi est-ce une affectation valide en sortant d'un objet littéral contenant une propagation ?

désolé.. les littéraux d'objets sont un cas particulier. mon exemple était faux. voici un meilleur exemple :

let obj = { a: "a", b:0, x: "X" };
let state: State = obj; // OK

La question ici est si plutôt subjective. Lorsque le compilateur voit let state:State = { a: "a", b:0, x: "X" } , il y a de fortes chances que x soit une faute de frappe, soit une propriété obsolète qui a été laissée de côté après la refactorisation, soit un type pour une propriété facultative, c'est pourquoi elle est signalée comme un Erreur.

cependant, si vous étalez un objet, disons let myConfig : State= { a: 1, ...myOtherBigConfigBag} , si le myOtherBigConfigBag a quelques propriétés dont vous ne vous souciez pas, vous avez juste besoin du a et du b , une erreur ici vous obligerait à garder ces deux interfaces synchronisées ou à effectuer un cast pour faire disparaître ces erreurs.

cela dit. nous devrions reconsidérer cette décision. déposé https://github.com/Microsoft/TypeScript/issues/12717 pour suivre cela.

Je vois. J'adore ton idée au #12717, c'est exactement ce que je pensais. En fait, j'aimerais un tel comportement même pour les accessoires de propagation, mais je peux voir votre point de vue selon lequel c'est très subjectif et pourrait être ennuyeux pour certains cas d'utilisation courants de JS.

@aaronbeall Je suis d'accord, ce serait ennuyeux pour les cas d'utilisation courants de JS... La plupart du temps, vous voulez juste vous assurer que l'objet a la forme de l'interface spécifiée et ne pas inspecter directement l'objet de propagation, l'implémentation actuelle est correcte IMO

Salut les gars, Félicitations pour la grande sortie! Il est maintenant temps de prendre un repos mérité... d'ailleurs, j'ai un problème avec l'opérateur de repos :)

En utilisant React, vous avez généralement un composant comme :

export interface MyLinkProps extends React.HTMLAttributes {
    myUrl: string
}

class MyLink{

    render(){
      const {myUrl, ...attrs } = this.props;
     return <a href={calculate(myUrl)} ...attrs>Click here</a>;
   }
}

Le problème est que lorsque vous passez la souris sur attrs vous obtenez la liste de toutes les propriétés (des centaines) au lieu de React.HtmlAttributes.

Je sais que le tapuscrit est structurellement typé et tout ça, mais serait-il possible d'attribuer un type explicite à la variable rest?

Quelques alternatives :

    const {myUrl, ...attrs as React.HtmlAttributes } = this.props; //Is not really a casting

    const {myUrl, ...attrs : React.HtmlAttributes } = this.props; //conflicts with ES6?

    const attrs : React.HTMLAttributes; 
    const { myUrl, ...attrs } = this.props;  //re-declare the variable

@bondz Eh bien, ce n'est pas vrai dans 100% des utilisations de mon projet. :) Mais dans un autre projet, cela peut être très ennuyeux. Dans mon cas, j'utilise Redux et React et j'utilise beaucoup l'état immuable, ce qui signifie que pour mettre à jour ou créer des objets d'état, je dois copier tous les accessoires sur un nouvel objet littéral... dans tous les cas, je veux une sécurité de type à 100% que je J'essaie de copier les bonnes données sur l'interface d'état cible. Actuellement, j'utilise des fonctions pour assurer cette sécurité, mais je préférerais utiliser la propagation d'objets car c'est plus propre (syntaxe lisible, expressive et standard.) structures, donc je vois à quel point c'est assez subjectif. Je pense que la suggestion #12717 est un bon compromis (et plus cohérente avec la sécurité de type littéral d'objet existant.)

https://github.com/Microsoft/TypeScript/issues/2103#issuecomment -145688774
Nous voulons attendre que la proposition atteigne l'étape 3 avant d'aborder cette question.

On dirait que c'est déjà l'état 3, un plan pour soutenir ça ?

Au fait, nous utilisons VSCode principalement pour le développement ES, pas encore TS :)

@evisong cette fonctionnalité a été expédiée et est déjà disponible dans la dernière version de vsCode. Mettez à jour votre vsCode vers la version 1.8

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

CyrusNajmabadi picture CyrusNajmabadi  ·  3Commentaires

dlaberge picture dlaberge  ·  3Commentaires

DanielRosenwasser picture DanielRosenwasser  ·  3Commentaires

bgrieder picture bgrieder  ·  3Commentaires

MartynasZilinskas picture MartynasZilinskas  ·  3Commentaires