嵌套对象 -> 元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型

Posted

技术标签:

【中文标题】嵌套对象 -> 元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型【英文标题】:Nested Object -> Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 【发布时间】:2020-08-24 18:09:07 【问题描述】:

我有一个反应表单组件,我正在尝试将其重写为打字稿。我正在尝试在 for 循环中检索另一个对象中的一个对象,但我不断收到以下错误

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 

我尝试了以下问题中提出的解决方案,但我仍然无法找到有效的解决方案,并且我不希望在 tsconfig.json 中将 noImplicitAny 设置为 false

    TypeScript: Object.keys return string[]

    TypeScript TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'

    element implicitly has an 'any' type because type '0' has no index signature.

有问题的代码是 - 有问题的区域可以在底部附近找到:

import React from 'react';

import Button from '../../UI/Button/Button';
import Input from '../../UI/Input/Input';


type Config = 
    elementType: string;
    elementConfig: 
        type: string;
        placeholder: string;
        options: 
            value: string;
            displayValue: string;
        ;
    ;
    value: string;
    validation: 
        required: boolean;
        isEmail?: boolean;
        minLength?: number;
    ;
    valid: boolean;
    touched: boolean;
    fieldActive: boolean;
    // [key: string]: string | Object;


interface SignInFormProps 
    isSignIn: boolean;


interface SignInFormState 
    controls: 
        email: Config;
        password: Config;
    ;
    isSignUp: boolean;
    [key: string]: boolean | Object | Config;



class SignInForm extends React.Component<SignInFormProps, SignInFormState> 
    state = 
        controls: 
            email: 
                elementType: 'input',
                elementConfig: 
                    type: 'email',
                    placeholder: 'Your Email',
                    options: 
                        value: '',
                        displayValue: ''
                    ,
                ,
                value: '',
                validation: 
                    required: true,
                    isEmail: true
                ,
                valid: false,
                touched: false,
                fieldActive: false
            ,
            password: 
                elementType: 'input',
                elementConfig: 
                    type: 'password',
                    placeholder: 'Password',
                    options: 
                        value: '',
                        displayValue: ''
                    ,
                ,
                value: '',
                validation: 
                    required: true,
                    minLength: 6
                ,
                valid: false,
                touched: false,
                fieldActive: false
            
        ,
        isSignUp: true
    

    private activateField = ( controlName: keyof SignInFormState['controls'] ) => 
        do stuff...
    

    ...

    render() 
        const formElementsArray: id: string, config: Config[] = [];

        // ################ The config value is causing the error ################
        for ( let key in this.state.controls ) 
            formElementsArray.push(
                id: key,
                config: this.state.controls[key] as Config
            );
        

        let form = formElementsArray.map( formElement => (
            <Input
                blur= ( event ) => this.disableFocus(event, formElement.id) 
                changed= ( event ) => this.inputChangedHandler(event, formElement.id) 
                elementConfig=formElement.config.elementConfig
                elementType=formElement.config.elementType
                fieldActive=formElement.config.fieldActive
                focus= () => this.activateField(formElement.id) 
                invalid=!formElement.config.valid
                key=formElement.id
                shouldValidate=formElement.config.validation.required
                touched=formElement.config.touched
                value=formElement.config.value />
        ));

如果有人对如何在明确定义类型且不使用任何类型的情况下解决此问题有任何想法,那将很有帮助。

【问题讨论】:

【参考方案1】:

首先,没有一个很好的方法可以做到这一点,它仍在讨论中:https://github.com/Microsoft/TypeScript/issues/3500

以下是解决问题的 2 种潜在方法。

    在循环外声明键:
const formElementsArray:  id: string; config: Config [] = [];
let key: keyof typeof this.state.controls;
for (key in this.state.controls) 
  formElementsArray.push(
    id: key,
    config: this.state.controls[key],
  );

    使用 Object.keys 并将密钥转换为所需的类型:
const formElementsArray:  id: string; config: Config [] = (Object.keys(
  this.state.controls
) as (keyof typeof this.state.controls)[]).map((key) => (
  id: key,
  config: this.state.controls[key],
));

您还可以通过使用控制键的枚举来使其更清晰

enum ControlKey 
  email = "email",
  password = "password",


interface SignInFormState 
  controls: 
    [key in ControlKey]: Config;
  ;
  isSignUp: boolean;
  [key: string]: boolean | Object | Config;

然后

1b.

const formElementsArray:  id: string; config: Config [] = [];
let key: ControlKey;
for (key in this.state.controls) 
  formElementsArray.push(
    id: key,
    config: this.state.controls[key],
  );

2b.

const formElementsArray:  id: string; config: Config [] = (Object.keys(
  this.state.controls
) as ControlKey[]).map((key) => (
  id: key,
  config: this.state.controls[key],
));

希望对你有帮助

【讨论】:

以上是关于嵌套对象 -> 元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用命名数组的接口:元素隐式具有“任何”类型,因为索引表达式不是“数字”类型

Object.keys 迭代导致 Typescript 错误“元素隐式具有‘任何’类型,因为索引表达式不是‘数字’类型”

元素隐式具有“任何”类型,因为类型“窗口”没有索引签名?

元素隐式具有“任何”类型,因为类型的表达式

映射打字稿参数:绑定元素“列”隐式具有“任何”类型

元素隐式具有“任何”类型,因为类型的表达式