Description
Try with newest TypeScript
TypeScript Version: 3.7.0-dev.20191018
Result: has not been fixed.
Search Terms:
typescript indexable type string keys or number keys
Code
enum PROPERTIES_TYPES {
NUMBER = "NUMBER",
STRING = "STRING"
// ETC.
}
interface IStringPropertySpecification {
type: PROPERTIES_TYPES.STRING;
required: boolean;
nullable?: boolean;
newName?: string;
emptyStringIsAllowed: boolean;
allowedValues?: Array<string>;
invalidValueSubstitution: string;
defaultValue?: string;
}
interface IObjectDataSpecification__StringKeys {
nameForLogging: string;
properties: {
[propertyName: string]: IStringPropertySpecification;
};
}
interface IObjectDataSpecification__NumberKeys {
nameForLogging: string;
properties: {
[propertyName: number]: IStringPropertySpecification;
};
}
type ObjectDataSpecification = IObjectDataSpecification__StringKeys | IObjectDataSpecification__NumberKeys;
const dataSpecification: ObjectDataSpecification = {
nameForLogging: "Test",
properties: {
foo: "asdfsadffsd" // Valid!!! No type errors!
}
};
Expected behavior:
The error occurrence. I suppose, it must be:
TS2322 Type 'string' is not assignable to type ObjectDataSpecification
Actual behavior:
TypeScript ignores this error. However, my PhpStorm knows right autocompletes:
Playground Link: https://jsfiddle.net/pfg1mq96/
Why I need so strange type as ObjectDataSpecification?
The ObjectDataSpecification
has been created for external data validation. It's known in advance, which type external data SHOULD be, but it's unknown in advance, which data ACTUALLY WILL BE. If data satisfies ObjectDataSpecification
, it will be cast as below:
const validData: IValidData = rawData as IValidData;
In above case, IValidData
will be:
interface IValidData { foo: string; }
Normally, programmers should not create type like:
type ConfusingType {
1: string;
foo: number;
}
However I can't hope for high-quality API in the team work, The API team could define ANYTHING includes strange structure like above ConfusingType
. Even it happens, I must to describe the ConfusingType
with my ObjectDataSpecification
. It will be:
const dataSpecification: ObjectDataSpecification = {
nameForLogging: "ConfusingType ",
properties: {
1: {
type: PROPERTIES_TYPES.STRING,
required: true,
emptyStringIsAllowed: false,
invalidValueSubstitution: "---"
},
foo: {
type: PROPERTIES_TYPES.NUMBER,
required: true,
numberType: NUMBER_TYPES.NATURAL_NUMBER,
invalidValueSubstitution: 1
}
}
};
Then, my library validates external data according to dataSpecification
.