How to rewrite code to avoid TSLint "object access via string literals"
TypescriptTslintTypescript Problem Overview
I'm pretty new to TypeScript and I would like to know if there exists a good way to rewrite code to avoid TSLint error "object access via string literals is disallowed" in the following code
interface ECType
{
name: string;
type: string;
elementType?: string;
}
export var fields: { [structName: string]: Array<ECType>; } = { };
class ECStruct1 {
foo: string;
bar: number;
baz: boolean;
qux: number;
quux: number;
corge: ECStruct2[];
grault: ECStruct2;
constructor() {
...
}
}
fields['ECStruct1'] = [ { name: 'foo', type: 'string' }, { name: 'bar', type: 'int' }, { name: 'baz', type: 'bool' }, { name: 'qux', type: 'long' }, { name: 'quux', type: 'ulong' }, { name: 'corge', type: 'array', elementType: 'ECStruct2' }, { name: 'grault', type: 'ECStruct2' }];
Update: At the end the content above will be part of a self-generated file with more than 300 ECStruct
s, so I would like to have the class definition (e.g. ECStruct1
) followed by its meta-description (e.g. fields['ECStruct1']
).
Typescript Solutions
Solution 1 - Typescript
You have a couple options here:
1) Just disable the rule
/* tslint:disable:no-string-literal */
whatever.codeHere()
/* tslint:enable:no-string-literal */
2) Use a variable instead of a string literal
// instead of
fields['ECStruct1'] = ...
// do something like
let key = 'ECStruct1';
fields[key] = ...
3) Write/Generate an explicit interface
See MartylX's answer above. Essentially:
interface ECFieldList {
ECStruct1: ECType[];
}
export var fields:ECFieldList = {
ECStruct1: [
...
Any of these are reasonable solutions, although I'm not as much of a fan of #2 because it's mangling up your code for no good reason. If you're generating code anyways, perhaps generating a type for fields
as in #3 is a good solution.
Solution 2 - Typescript
You can get rid of the rule. Look for tslint.json
, the add a property "no-string-literal"
with false
, in rules
::
{
"rules": {
"no-string-literal": false,
... other rules ...
Solution 3 - Typescript
Just use template literal annotation.
fields[`ECStruct1`]
Solution 4 - Typescript
What about this way? I don't know if you need the indexer ([structName: string]: Array<ECType>;
) or not.
interface ECType {
name: string;
type: string;
elementType?: string;
}
interface ECFieldList {
ECStruct1: ECType[];
}
export var fields:ECFieldList = {
ECStruct1: [
{name: 'foo', type: 'string'},
{name: 'bar', type: 'int'},
{name: 'baz', type: 'bool'},
{name: 'qux', type: 'long'},
{name: 'quux', type: 'ulong'},
{name: 'corge', type: 'array', elementType: 'ECStruct2'},
{name: 'grault', type: 'ECStruct2'}
]
};
Solution 5 - Typescript
Probably not the best option, but using
fields['ECStruct1'.toString()]
works too
Solution 6 - Typescript
A simple way is to define a variable to hold the value of ECStruct1:
const sampleName = 'ECStruct1';
and then, get access to the object by using the variable as index:
fields[sampleName] ...
Solution 7 - Typescript
I have faced the same error. but i tried to make use of the type
of Headers
of Request
object and it worked for me. Below is how I managed to resolve the issue.
const objToAdd: { [key: string]: string } = {};
objToAdd.type = 'typeToAdd';
objToAdd.key = 'keyToAdd';
objToAdd.value = 'valueToAdd';
if you see the type { [key: string]: string }
tells the TSLint that this object takes keys and values of type string.
Similarly, { [key: string]: any }
types specifies that the keys are of string
type and values of are of any
type