-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Splitting computed and named properties in an interface into two categories #8597
Comments
When you index into a value of this type using a string, the compiler does not know if its a computed property or a named property. e.g.: var x: string = getName();
var test: IComputedTest;
var y = test[x] // what is the type of `y`? The index signature |
Hi, therefor i had an assertion pattern, that checks if the right value is set. I mean, that it could be possible to have static key name that can have a specific type? For example this works fine for me: interface IComputetTest {
[name: string]: string|number;
numberProperty: number;
}
let x:IComputetTest = {
numberProperty: 1
};
let y = function():string {
return 'numberProperty'
}
x[y()] = '2a'; // can't check, so string|number fallback (better string only but ok)
x.numberProperty = 1; // only number allowed This example work quite well, but I think I have to accept, that strings and numbers must be allowed then. Ok, I played a litte bit with interfaces and think I get a good solution: interface IExpression {
[key:string]: IExpression|Array<IExpression>|Array<string|number|boolean>|string|number|boolean;
$in?: Array<string|number|boolean>;
$or?: Array<IExpression>;
$and?: Array<IExpression>;
$lt?: number;
}
var testIFind: IExpression;
testIFind = {
$lt: 1,
a: {
$lt: 4
}
}
// https://docs.mongodb.com/manual/reference/operator/query/or/
testIFind = { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] };
// https://docs.mongodb.com/manual/reference/operator/query/and/
testIFind = { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } } ] };
testIFind = {
$and : [
{ $or : [ { price : 0.99 }, { price : 1.99 } ] },
{ $or : [ { sale : true }, { qty : { $lt : 20 } } ] }
]
}; That work nearly as well as I intended and it is fine to create objects and allows me to check if the static object definition is correct by compiler. But is there a way around writing string|number|boolean again and again? |
I posted an experimental idea for 'rest' index signatures. The particular comment linked described a 'typed' variant that may help here: interface IComputedTest {
numberProperty: number;
[name: ...string]: string;
} There are other ideas included there, like string literal types as keys and a hypothetical It is possible to make a more 'basic' proposal, which would only include |
In short I forgot to mention that the compiler fallback to computed if you use brackets. The compiler should so only check static keys that could have other types than computed or dynamic properties. At now it works if the dynamic property has also the type of the static key and it will check as well. |
@malibuzios This signature idea is much more I want. But I subscribed it. |
I do not think there is a way to make this really work for the same type. there is nothing that the compiler can do statically to grantee a string value is not the name of one of the known properties.. interface IComputedTest {
numberProperty: number;
[name: ...string]: string;
}
var test: IComputedTest ;
var s = "numberProperty";
test[s]; // it is a number at runtime, regardless of the index signature you defined. |
@Thomas-P the work around is to use two types. e.g.: type IComputetTest = {numberProperty: number} & {[name: string]: string;};
var x: IComputetTest;
x.numberProperty; // number
x["other"]; // string |
I couldn't follow the explanation. The intersection type workaround does work, though isn't very elegant or intuitive to understand (even for someone deeply familiar with the language, there is still a significant doubt it would error and not clear what it should do exactly). The first example had a variable with a Using the intersection workaround with the same exact scenario as the first example doesn't really help: type IComputetTest = {numberProperty: number} & {[name: string]: string;};
declare var x: IComputetTest;
x.numberProperty; // number, with both approaches
let s = "numberProperty";
let y = x[s]; // 'y' gets type string -> the intersection type doesn't really help here. (perhaps something like #1295 could help here to correctly resolve the |
[tested on Thinking about this further, despite the fact that this intersection type: { [key: string]: string } & { prop: number } doesn't currently error, it isn't really logically consistent.
Combining the two would mean that key This simpler example demonstrates this more clearly: let a: { prop: string } & { prop: number };
a.prop = 1; // error: type 'number' is not assignable to 'string & number'
a.prop = "hi"; // error: type 'string' is not assignable to 'string & number' |
Hi @malibuzios and @mhegazy, the Issue is already closed but I have found out that in one case TypeScript already works as I expected, but a also little different: interface IWithOther {
[key: string]: Object;
property: number;
} So I got an any without using any and now I don't want you to change this behavior, because then my little hack for the type description files won't work. But I will mention that I use TypeScript for the static type checking and that is awesome. JavaScript allows us to add some properties to an object and that is something computed properties will also do. We have two things that TypeScript do as it expect. Check static type and check dynamic/computed types. So why do I have to say all computed types must also have all the static property types? That is something that I not expected, because these are two worlds. @malibuzios I think for your example it awaits a property that have a string and a number type. But by intersecting there should be a used or or the last one. Looks like a bug, but should be tested. It reminds me to this one: interface IVal {
string;
number;
}
let a: IVal;
a= 1;
a= '1'; It has the same effect. Instead of using the or operator it awaits a value that I could not generate. So there are some errors. |
Hi,
I have a question about computed properties. I have an interface that can have mutliple computed properties which can have a string as value and some specified properties that should have a number as their value. So my interface looks like this.
On building the interfaces like this, I thought that they could work with a specification priority. So computed priority is very low and a numberProperty than overwrite the rule for the computed property. But since I realized that it would not work like this for now, my question is how can I solve the problem, that I have specific keys with other types and computed keys with there own type?
Is there a way around them?
The text was updated successfully, but these errors were encountered: