TS报错:不能将类型“{ readonly [x: number]: string; toString: () => string; ...”分配给类型“EpPropMergeType<...怎么解决

 1. 报错信息展示

给el-inut绑定model值时

报错:不能将类型“{ readonly [x: number]: string; toString: () => string; charAt: (pos: number) => string; charCodeAt: (index: number) => number; concat: (...strings: string[]) => string; indexOf: (searchString: string, position?: number | undefined) => number; ... 42 more ...; [Symbol.iterator]: () => IterableIterator<...>; } | unde...”分配给类型“EpPropMergeType<(new (...args: any[]) => string | number) | (() => string | number | null | undefined) | ((new (...args: any[]) => string | number) | (() => string | number | null | undefined))[], unknown, unknown>”。

input.vue.d.ts(211, 14): 所需类型来自属性 "modelValue",在此处的 "Partial<{ readonly disabled: boolean; readonly id: string; readonly type: string; readonly modelValue: EpPropMergeType<(new (...args: any[]) => string | number) | (() => string | number | null | undefined) | ((new (...args: any[]) => string | number) | (() => string | ... 2 more ... | undefined))[], unknown, unknown..." 类型上声明该属性

2. 报错可能性分析

好久前学的ts 没使用之后忘差不多了,js的类型和原型也没之前那么重视; 刚开始在想 怎么这么长一大段,于是猜测报错的可能性是什么:

  1. 接口的使用没掌握好。
  2. 类型断言也没搞懂。
  3. element-plus版本。
  4. 定义类型不对。

接口的使用

定义一个接口通过关键词interface实现,此时可以对接口的属性进行类型设置。

1. 接口的扩展

用于将一个接口的属性和方法继承到另一个接口中 。当一个接口中需要用到另一个属性及其方法时,可通过extends扩展第一个接口

// 定义第一个接口
interface InterfaceA {
  id: number;
  name: string;
}

// 定义第二个接口,扩展第一个接口
interface InterfaceB extends InterfaceA {
  description: string;
  isActive: boolean;
}

// 使用示例
const example: InterfaceB = {
  id: 1,
  name: 'Example',
  description: 'This is an example',
  isActive: true,
};
2. 接口的合并

用于将多个接口合并成一个接口

// 定义第一个接口
interface InterfaceA {
  id: number;
  name: string;
}

// 定义第二个接口
interface InterfaceB {
  description: string;
  isActive: boolean;
}

// 合并接口
interface CombinedInterface extends InterfaceA, InterfaceB {}

// 使用示例
const example: CombinedInterface = {
  id: 1,
  name: 'Example',
  description: 'This is an example',
  isActive: true,
};
3. 类型别名

灵活地组合接口类型

// 定义第一个接口
interface InterfaceA {
  id: number;
  name: string;
}

// 定义第二个接口
interface InterfaceB {
  description: string;
  isActive: boolean;
}

// 组合接口类型
type CombinedType = InterfaceA & InterfaceB;

// 使用示例
const example: CombinedType = {
  id: 1,
  name: 'Example',
  description: 'This is an example',
  isActive: true,
};
4. 读写属性

默认属性是读写的,用 readonly 来定义只读属性

// 只读接口
interface ReadOnlyInterface {
  readonly id: number;
  readonly name: string;
}

// 可读写接口
interface ReadWriteInterface extends ReadOnlyInterface {
  description: string;
  isActive: boolean;
}

// 使用示例
const example: ReadWriteInterface = {
  id: 1,
  name: 'Example',
  description: 'This is an example',
  isActive: true,
};

// 只读属性不能被修改
example.id = 2; // 错误:id 是只读属性
5. 嵌套对象类型

使得属性的值符合指定接口的结构 提高代码复用性和类型安全性,同时也支持灵活的读写权限管理

 

// 可读写属性
interface InterfaceA {
  id: number;
  name: string;
}

// 定义第二个接口,info 属性是 InterfaceA 类型,但标记为只读
interface InterfaceB {
  readonly info: InterfaceA;  // info 属性是只读的
  description: string;
}

const example: InterfaceB = {
  info: {
    id: 1,
    name: 'John Doe'
  },
  description: 'A description'
};

// 只能读取 info,不能修改
example.info.name = 'Jane Doe'; // 错误:info 是只读的

类型断言

TypeScript 提供了两种类型断言的语法:

  1. 尖括号语法(旧语法)
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
  1. as 语法(推荐语法)
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

建议使用 as 语法,因为它与 JSX 语法更兼容,并且更具可读性。

示例

1. 基本类型断言

当你有一个 any 类型的变量,且你知道它实际是一个 string 类型:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;  // 使用 'as' 语法
// 或
let strLength2: number = (<string>someValue).length;  // 使用尖括号语法
2. 断言为对象类型

当你知道某个对象符合特定接口或类型,但 TypeScript 编译器无法推断:

interface Person {
  name: string;
  age: number;
}

let obj: any = { name: "John", age: 30 };

// 断言 obj 为 Person 类型
let person = obj as Person;

console.log(person.name); // John
console.log(person.age);  // 30
3. 处理 DOM 元素

在处理 DOM 元素时,TypeScript 可能不知道具体的元素类型。你可以使用类型断言来指定:

let inputElement = document.querySelector('input') as HTMLInputElement;

inputElement.value = "New Value";
4. 函数类型断言

当你需要断言某个函数的返回类型:

function getValue(): any {
  return "some value";
}

let value = getValue() as string; // 断言返回值为 string 类型
console.log(value.length);
注意事项
  • 类型断言并不会进行类型检查:它仅仅是告诉 TypeScript 编译器“相信我,我知道这个值是什么类型”。实际运行时如果类型不匹配,可能会导致错误。
  • 使用类型断言时要小心:确保你对断言的类型是正确的,否则可能会引发运行时错误。
  • 避免过度使用:过度使用类型断言可能会隐藏真实的类型错误,导致难以维护的代码。尽量依赖于 TypeScript 的类型推断和类型检查功能,只有在确实需要时使用类型断言。

element-plus版本

检查了一下也是适配的

"element-plus": "^2.8.3",
"vue": "^3.4.37"

定义类型不对

export interface wmFont {
    color?: String // 水印文字颜色
    fontSize?: String // 水印文字大小
    fontStyle?: 'none' | 'normal' | 'italic' | 'oblique' // 水印文字样式
    fontWeight?: 'normal' | 'light' | 'weight' | number // 水印文字粗细
    fontFamily?: String // 水印文字字体
}

可能大家一眼就看出来了问题所在。但是我当时眼瞎是真找不着而且也没往这方面想。

前前后后查看了接口定义,接口嵌套,已经定义的变量类型均无果。

此时看到了报错提示:

[x: number]: string;[1]

toString: () => string;

charAt: (pos: number) => string;

这些不都是String对象上的方法吗 这就不得不提string和String的区别了

解决问题关键
string和String的区别

简单来说:string表示原生类型,而String表示对象。

string(基本类型)

  • string 是 TypeScript 中的原始类型(primitive type),它表示的是 JavaScript 中的基本数据类型——字符串。
  • 当你在 TypeScript 中使用 string 时,它表示的是一个基本的、不可变的字符串值。

示例:

let basicString: string = "Hello, world!";

在这个例子中,basicString 是一个简单的字符串。

String(对象类型)

String是不可变对象,这意味着对String对象的任何操作,如修改、连接、替换等,实际上都是通过创建新的String对象来实现的,而不是直接修改原始对象。这种设计使得String对象具有线程安全性和内存安全性,因为多个线程可以同时访问和操作同一个不可变的String对象,而不会出现数据不一致的问题。

这也是报错的根本原因所在。

  • String 是 JavaScript 中的内置对象类型(object type),它是 string 类型的封装对象。当你使用 new String() 时,它会创建一个字符串对象,而不是一个基本的字符串值。
  • String 通过构造函数 new String() 创建,属于引用类型,而不是基本类型。

示例:

let objectString: String = new String("Hello, world!");

在这个例子中,objectString 是一个字符串对象,而不是基本的字符串值。

区别总结:

  • string 是原始类型,表示基本的字符串值,没有任何的方法,性能更好,通常应该优先使用。
  • String 是对象类型,表示包装后的字符串对象,除非有特殊需求(如需要使用某些对象方法),否则不建议使用。

使用建议:

一般情况下,应该使用 string 而不是 String,因为 string 是更轻量、更高效的基本类型,而 String 是一个对象,会增加不必要的性能开销。

举例:

let basicString: string = "hello";
let objectString: String = new String("hello");

console.log(typeof basicString); // "string"
console.log(typeof objectString); // "object"

如上所示,basicStringstring 类型,而 objectStringobject 类型。

3. 解决措施

将接口的类型定义进行修改。将String改为string

export interface wmFont {
    color?: string // 水印文字颜色
    fontSize?: string // 水印文字大小
    fontStyle?: 'none' | 'normal' | 'italic' | 'oblique' // 水印文字样式
    fontWeight?: 'normal' | 'light' | 'weight' | number // 水印文字粗细
    fontFamily?: string // 水印文字字体
}

4. 另外

[1] interface StringArray 是一个 TypeScript 的接口定义,它表示一个数组,数组中的每个元素都是字符串类型。

interface StringArray {
  [index: number]: string;
}

含义

  • interface StringArray: 定义了一个名为 StringArray 的接口。
  • [index: number]: string;: 这是一个索引签名。它表示用任意数字类型的索引(即 index),可以访问到一个 string 类型的值。

用法

const myArray: StringArray = ["苹果", "香蕉", "樱桃"];
console.log(myArray[0]); // 输出: 苹果
console.log(myArray[1]); // 输出: 香蕉

StringArray 接口定义了一个用数字作为索引,字符串作为值的数组结构。实际上,它和 TypeScript 内置的 string[] 类型是相同的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值