TypeScript Version: 3.0.1
Code
import Sequelize from 'sequelize';
import { DbInterface } from'typings/DbInterface';
import { UserFactory } from './User';
import { PostFactory } from './Post';
import { CommentFactory } from './Comment';
export const createModels = (sequelizeConfig: any): DbInterface => {
const { database, username, password, params } = sequelizeConfig;
const sequelize = new Sequelize(database, username, password, params);
const db: DbInterface = {
sequelize,
Sequelize,
Comment: CommentFactory(sequelize, Sequelize),
Post: PostFactory(sequelize, Sequelize),
User: UserFactory(sequelize, Sequelize)
};
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) { //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DbInterface'. No index signature with a parameter of type 'string' was found on type 'DbInterface'.
db[modelName].associate(db); //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DbInterface'. No index signature with a parameter of type 'string' was found on type 'DbInterface'.
}
});
return db;
};
This is a question, not a bug, please use SO for questions. (see this it will help)
im sorry, thanks btw for the tips. im a newbie
// bad
const _getKeyValue = (key: string) => (obj: object) => obj[key];
// better
const _getKeyValue_ = (key: string) => (obj: Record<string, any>) => obj[key];
// best
const getKeyValue = <T extends object, U extends keyof T>(key: U) => (obj: T) =>
obj[key];
Bad - the reason for the error is the object
type is just an empty object by default. Therefore it isn't possible to use a string
type to index {}
.
Better - the reason the error disappears is because now we are telling the compiler the obj
argument will be a collection of string/value (string/any
) pairs. However, we are using the any
type, so we can do better.
Best - T
extends empty object. U
extends the keys of T
. Therefore U
will always exist on T
, therefore it can be used as a look up value.
@alexandermckay What if I have this scenario:
type props = {
type: string
}
const style = styles[props.type]
const styles = StyleSheet.create({
base: {
...spacing.medium,
padding: 10,
textAlign: "center",
textAlignVertical: "center",
fontWeight: "bold",
fontSize: 18,
height: 50,
},
primary: {
backgroundColor: colors.purple,
color: colors.white,
},
secondary: {
backgroundColor: "transparent",
color: colors.purple,
borderColor: colors.purple,
borderWidth: 2,
},
}
It complains:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type styles
Same question here, I have
const LEVEL_DEBUG = 1;
const LEVEL_FINE = 2;
const LOG_LEVELS = {
info: LEVEL_INFO,
debug: LEVEL_DEBUG,
fine: LEVEL_FINE,
};
let logLevel: string = environment.logLevel;
if (!logLevel) {
logLevel = 'info';
}
let _level = LOG_LEVELS[logLevel.toLowerCase()]; // here it complains
@greenlaw110
Try to get the key value by using @alexandermckay's method:
const LEVEL_DEBUG = 1;
const LEVEL_FINE = 2;
const LOG_LEVELS: {[key:string]: number} = {
debug: LEVEL_DEBUG,
fine: LEVEL_FINE,
};
let logLevel:string = 'debug';
if (!logLevel) {
logLevel = 'info';
}
const getKeyValue = <T extends object, U extends keyof T>(obj: T) => (key: U) =>
obj[key];
let _level = getKeyValue(LOG_LEVELS)(logLevel);
console.log(_level); // 1
Just found this blog post, which was very helpful, and wanted to paste some code here that I think is slightly more straight forward than the code included here so far. If you have the following object:
const unitsOfTime = {
millisecond: 1,
second: 60,
hour: 60 * 60,
day: 24 * 60 * 60,
month: 30 * 24 * 60 * 60,
year: 365 * 24 * 60 * 60
};
You can declare types for the keys and values in that object like so:
const unitsOfTime: { [unit: string]: number } = {
millisecond: 1,
second: 60,
hour: 60 * 60,
day: 24 * 60 * 60,
month: 30 * 24 * 60 * 60,
year: 365 * 24 * 60 * 60
};
Hey, if I do this my object will have the following shape when I hove over it:
const unitsOfTime: {
[unit: string]: number;
}
so auto-complete is no longer available, am I missing something?
The workarounds provided here are not recommended for Object.keys. If you really want to iterate over known values on an object, you can't know that the object doesn't have additional properties at runtime. I've provided a TypeScript Playground example that demonstrates the runtime error that can occur.
In addition to the answers, people could also try to use interfaces :)
Here is an example, hope it helps:
export interface IMapping {
[propertyName: string]: string;
}
const mapping: IMapping = {
apples: '$5',
oranges: '$4',
}
// some code
const fruit: string = await getFruitFromInput();
const price: string = mapping[fruit];
return price;
Most helpful comment
Bad - the reason for the error is the
object
type is just an empty object by default. Therefore it isn't possible to use astring
type to index{}
.Better - the reason the error disappears is because now we are telling the compiler the
obj
argument will be a collection of string/value (string/any
) pairs. However, we are using theany
type, so we can do better.Best -
T
extends empty object.U
extends the keys ofT
. ThereforeU
will always exist onT
, therefore it can be used as a look up value.