object
Cette proposition décrit un nouveau type primitif pour dactylographié object
.
L'API de base de JavaScript contient des fonctions qui prennent object
comme paramètre:
Object.getPrototypeOf
Object.getOwnPropertyDescriptor
Object.create
Actuellement, il n'y a aucun moyen dans le typographie d'empêcher de passer d'autres types primitifs ( string
, number
, etc ...) à ces fonctions.
Par exemple Object.create('string')
est une instruction dactylographiée parfaitement valide, même si elle aboutit à une erreur.
Créer un nouveau type primitif object
permettrait de modéliser plus correctement la signature de ces fonctions, et de chaque fonction qui partage une contrainte similaire.
Le type object
est l'équivalent de {}
moins l'assignabilité d'un autre type de base, ce qui signifie que:
object
object
{}
et any
Ce comportement est cohérent avec le fonctionnement de javascript, le type représente chaque valeur qui respecte la contrainte typeof value === 'object'
plus undefined
.
Une nouvelle protection de type doit être introduite pour object
: typeof value === 'object'
.
En option, le compilateur peut également accepter la comparaison avec la fonction Object
cast: Object(value) === value
.
Il serait utile de lister certaines API autres que les fonctions Object.
qui en bénéficieraient.
Dans l'API du noyau javascript, sauf à partir de Object
peut-être que certaines constructions es6 en bénéficieront (WeakMap, Proxy, etc.).
Mais par exemple, chaque fonction de collecte de soulignement gagnerait également un meilleur typage, un framework comme React utilise une méthode 'setState' qui n'accepte que des objets ou null
, ImmutableJS, Mori, etc.
Edit: la collection de soulignements fonctionne avec tous les types
Discussion lors de la réunion d'examen des suggestions. Tout cela a du sens, mais nous devons justifier la complexité d'un nouveau type primitif par le nombre d'erreurs / la richesse de la description qu'il est capable de fournir. En gros, plus d'exemples d'API qui ne peuvent pas fonctionner sur des primitives, en particulier celles qui ne sont pas des API "expertes" (par exemple, les proxies)
Poster plus comme référence que comme recommandation: clin d'oeil:
interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }
interface ObjectOnly { _primitiveBrand?: void; }
function fn(x: ObjectOnly) { }
// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);
+1 sur cette proposition. Je ne considérerais pas WeakMap
une API "experte", mais je considère que c'est une raison suffisante à elle seule pour l'implémenter. Puisque le runtime fait une distinction entre les types d'objets et les types primitifs, il est logique d'avoir une fonction dans TypeScript pour faire la distinction également.
Cette proposition résoudra également le problème de la saisie de "sacs d'objets" où chaque propriété est facultative, mais les autres types primitifs devraient être interdits.
Object.observe
nécessite également une cible non primitive: http://arv.github.io/ecmascript-object-observe/#Object.observe
Je pense que le titre est un peu déroutant puisqu'il mentionne le mot «primitif». Cela peut également être appelé _ "Type d'objet ECMAScript" _ ou _ "Type d'objet d'exécution" _. Ce qui serait assignable à partir de tout autre que les types primitifs (y compris le type undefined
et les symboles), les types de fonction ou de constructeur. Les critères pour ce qui est un type légal object
doivent être basés sur la garde suivante:
let isObject (x) => typeof x === "object";
Selon MDN , c'est la sortie de typeof
:
Indéfini : "non défini"
Null : "objet" (voir ci-dessous)
Boolean : "boolean"
Numéro : "nombre"
Chaîne : "chaîne"
Symbole (nouveau dans ECMAScript 2015) : "symbole"
Objet hôte (fourni par l'environnement JS) : dépendant de l'implémentation
Objet fonction (implémente [[Appel]] en termes ECMA-262) : "fonction"
Tout autre objet : "objet"
Sans ce type, il n'y a aucun moyen de faire correspondre correctement un type précis pour la garde mentionnée ci-dessus, pas même en tant que garde définie par l'utilisateur. Ceci est également essentiel pour une utilisation avec toute fonction qui nécessite strictement un objet qui a des propriétés et autorise for in
boucles et appels au prototype Object
, et pour implémenter des contraintes génériques comme T extends object
puis référencer en toute sécurité les propriétés ou utiliser les fonctions du prototype.
L'exclusion des fonctions et des constructeurs serait toutefois un peu limitative dans certains cas, il pourrait donc y avoir un autre type qui les inclurait également et appelé le _ "type d'objet non primitif" _. Une solution de contournement partielle pourrait être l'union object | Function
bien que des transtypages ou des gardes supplémentaires soient nécessaires pour le gérer correctement.
Accepter les PR. Cela semble être un problème courant; ce sera un changement radical pour quiconque est assez courageux pour avoir écrit interface object { ... }
. La mise en œuvre doit être simple et suivre les règles décrites ci-dessus.
Note latérale: nous nous demandons tous où a été @fdecampredon !
@RyanCavanaugh Changement de ville de travail, et malheureusement pas beaucoup de tapuscrit dans mon nouvel emploi: D
Génial. Je souhaite utiliser ce type dans TS1.8.
J'aimerais aussi voir quelque chose comme un type object
. Cependant, je me demande s'il doit être conforme à typeof value === 'object'
, car cela exclurait les fonctions. Au lieu de cela, il me semble que le type potentiel object
devrait refléter le type de langage Object, qui inclut des fonctions. Il y a plusieurs raisons à cela:
Object
.Je vais les prendre dans l'ordre.
Les API telles que WeakMap
qui n'acceptent que des objets acceptent le type de langage Object, pas seulement des objets simples. Ce qui suit est ok:
function theAnswer() {}
let map = new WeakMap();
map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42
Cela est aussi vrai pour les API personnalisées que pour les API intégrées. Si j'attends un objet, je veux généralement juste un ensemble de propriétés. Les fonctions ne sont que des ensembles de propriétés appelables.
Puisque Function
étend le constructeur Object
, nous pouvons également utiliser les méthodes statiques et d'instance disponibles sur Object
sur les fonctions. Par exemple, ce qui suit est possible:
class DeepThought {
static getAnswer() {
return 42;
}
}
let computer = Object.create(DeepThought);
console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]
Bien que l'exemple ci-dessus soit un peu idiot, il illustre simplement que les API qui utilisent les méthodes Object
interne pourraient tout aussi bien accepter des fonctions.
Je suggérerais donc que le type object
conforme à ce qui suit, qui correspond au type de langage Object (sauf qu'il inclut null
, mais il n'y a pas de protection contre null
dans TypeScript dans tout les cas).
function isObject(value) {
return typeof value === 'object' || typeof value === 'function';
}
J'ai un projet appelé Deep Map qui se répète à travers les paires clé-valeur d'objets imbriqués et transforme les valeurs primitives en cours de route. En tant que tel, il fait la distinction entre les types primitifs et non primitifs. J'ai dû définir une interface personnalisée NonPrimitive
, comme suit:
interface NonPrimitive {
[key: string]: any;
[index: number]: any;
}
export class DeepMap {
// ...
private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}
Ce n'est pas la première fois que je dois définir l'interface NonPrimitive
. Ce serait bien si je pouvais simplement faire ceci:
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
Comme je l'ai suggéré ci-dessus, je ne me soucie pas vraiment de savoir si le paramètre obj
est appelable ou non. Tout ce qui compte, c'est qu'il soit du type Object
_language_, c'est-à-dire qu'il s'agit d'un ensemble de propriétés dont je peux parcourir les paires clé-valeur.
Je conviens que les fonctions sont object
s. L'intention est d'exclure les primitives.
Ok, je pensais que ça devait être l'intention. Je pensais juste que je manquais peut-être quelque chose avec tout ce discours sur typeof value === 'object'
.
ce type object
autoriserait-il l'attribution de propriété ad hoc (comme any
)? Par exemple:
const foo: object = {};
foo.bar = 'baz';
Non
Quelle est la différence pratique entre
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
et
export class DeepMap {
// ...
private mapObject(obj: Object): Object { /* ... */ }
}
? (En utilisant object
vs Object
). Il me semble qu'un Function
s'étend de Object
, donc je ne vois pas pourquoi nous ne pouvons pas déjà faire ça. Peux-tu expliquer?
@trusktr Toutes les valeurs autres que null
et undefined
sont assignables au type Object
; une fonction qui accepte un Object
prendra une chaîne, un nombre, un booléen ou un symbole. Seules les valeurs non primitives peuvent être affectées à object
; passer une chaîne, etc., produira une erreur de compilation. Le type object
est utile lorsque nous attendons une valeur non primitive, mais où nous ne nous soucions pas de ses propriétés.
Commentaire le plus utile
+1 sur cette proposition. Je ne considérerais pas
WeakMap
une API "experte", mais je considère que c'est une raison suffisante à elle seule pour l'implémenter. Puisque le runtime fait une distinction entre les types d'objets et les types primitifs, il est logique d'avoir une fonction dans TypeScript pour faire la distinction également.Cette proposition résoudra également le problème de la saisie de "sacs d'objets" où chaque propriété est facultative, mais les autres types primitifs devraient être interdits.