typescript访问对象属性:元素隐式具有“any”类型

6ioyuze2  于 2023-04-07  发布在  TypeScript
关注(0)|答案(1)|浏览(175)

我正在处理一个代码库,我需要从step属性中访问一个值。

interface Car {
    name: string;
    age: number;
    color: string;
    step: {
        something: {
            onea: string;
            oneb: string;
        },
        anotherone: {
            twoa: string;
            twob: string;
        }
    }
};

const car: Car = {
    name: 'Some name',
    age: 200,
    color: 'something',
    step: {
        something: {
            onea: 'one a value',
            oneb: 'one b value'
        },
        anotherone: {
            twoa: 'two a value',
            twob: 'two b value',
        }
    }
};

const color = car.color;
const firstStep = car.step[color];

color将始终是step属性中的一个条目,在我的示例中返回一个错误。

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ something: { onea: string; oneb: string; }; anotherone: { twoa: string; twob: string; }; }'.
  No index signature with a parameter of type 'string' was found on type '{ something: { onea: string; oneb: string; }; anotherone: { twoa: string; twob: string; }; }'.

我所尝试的是在尝试获取值时使用typeof关键字,但仍然没有变化。

const firstStep = car.step[typeof color]
cngwdvgl

cngwdvgl1#

如果像这样注解car

const car: Car = {
    ⋯✂⋯
    color: 'something',
    ⋯✂⋯
};

那么你实际上是丢弃了初始化器中的任何更具体的信息。编译器只会知道carCar。这将允许你对car进行任何与Car的定义一致的更改,如

car.color = "purple";

编译器甚至不会试图跟踪car.color的实际值,它只是string

const color = car.color;
//const color: string

所以你不能用color索引car.step,因为编译器只允许你用已知的键"something" | "anotherone"索引。

const firstStep = car.step[color]; // error!

因此,如果你想让car从它的初始化值中跟踪特定的细节,那么你不能注解它。此外,如果你只是给它分配一个对象文字,编译器不会意识到你想让它注意color属性的文字类型。同样,它只会推断string,因此你可以改变它:

const car = {
    ⋯✂⋯
    color: 'something',
    ⋯✂⋯
};
car.color = "purple";
const color = car.color;
//const color: string
const firstStep = car.step[color]; // error!

哎呀。
你必须更进一步,要求编译器尽可能地将初始化器的值视为不可变或常量。你可以通过对该初始化器值使用constAssert来做到这一点:

const car = {
    ⋯✂⋯
    color: 'something',
    ⋯✂⋯
} as const;

现在,编译器将把color当作readonly属性,其类型是字符串文字"something"。现在,最后,这足以让剩下的代码工作:

const color = car.color;
// const color: "something"
const firstStep = car.step[color]; // okay

这很好,只是我们实际上根本没有使用Car,这意味着编译器不会捕获这样的错误

const car = {
    ⋯✂⋯
    age: "quite old",
    color: 'something',
    ⋯✂⋯
} as const; // no error

其中age是一个string而不是一个number。为了恢复不带注解的类型检查,我们可以使用satisfies操作符:

const car = {
    ⋯✂⋯
    age: "quite old",
    color: 'something',
    ⋯✂⋯
} as const satisfies Car; // error!
// ----------------> ~~~
// Types of property 'age' are incompatible.

错误已被捕获,我们可以更正它:

const car = {
    ⋯✂⋯
    age: 200,
    color: 'something',
    ⋯✂⋯
} as const satisfies Car; // okay

所以现在你拥有了两个世界的最佳选择!
Playground链接到代码

相关问题