TypeScript中keyof运算符类型含undefined的问题咨询
根据TypeScript文档,对象的keyof类型应为该对象所有键的联合类型,因此MetaObjectKey类型应该是"title" | "description" | "image" | "url" | "site_name" | "type"。但我把ogTags[i].split(':')[1]断言为MetaObjectKey后,给parsedMetaObject赋值时还是出现TypeScript错误:
Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'
这看起来和文档描述不符,疑似有问题。给出的代码如下:
import { HTMLElement, parse } from 'node-html-parser'; interface MetaObject { title: string; description: string; image: string; url: string; site_name: string; type: string; } type MetaObjectKey = keyof MetaObject; const ogTags = [ 'og:title', 'og:description', 'og:image', 'og:url', 'og:site_name', 'og:type' ]; export const generateHTMLNodes: (data: string) => HTMLElement = (data) => parse(data); export const extractMetaTagsFromHTMLRoot: ( rootElement: HTMLElement ) => MetaObject = (rootElement) => { const allMetaNodes = rootElement.querySelectorAll('meta'); const parsedMetaObject: MetaObject = { title: '', description: '', image: '', url: '', site_name: '', type: '' }; allMetaNodes.forEach((aMN) => { const i = ogTags.findIndex((e) => e === aMN.getAttribute('name')); if (i >= 0) { const key = ogTags[i].split(':')[1] as MetaObjectKey; parsedMetaObject[key] = aMN.getAttribute('content'); } }); return parsedMetaObject; }; export default generateHTMLNodes;
这个报错和keyof断言无关,问题出在aMN.getAttribute('content')的返回值类型上:
核心原因:
getAttribute方法的返回值是string | undefined——当目标meta标签没有content属性时就会返回undefined,但你的MetaObject接口要求所有属性必须是string类型,不允许undefined,因此TypeScript抛出了类型不匹配的错误。几种可行的解决方式:
- 兜底处理
undefined,确保赋值为字符串(空字符串兜底):parsedMetaObject[key] = aMN.getAttribute('content') || ''; - 若能确定对应meta标签一定存在
content属性,可使用非空断言强制告知TypeScript该值不会为undefined:parsedMetaObject[key] = aMN.getAttribute('content')!; - 更严谨的写法:先判断
content是否存在,再执行赋值:const content = aMN.getAttribute('content'); if (content) { parsedMetaObject[key] = content; }
- 兜底处理
另外,你对ogTags[i].split(':')[1]的类型断言是合理的,因为ogTags中的元素拆分后确实都是MetaObjectKey的成员,TypeScript无法自动推断这一点,手动断言完全没问题。
内容的提问来源于stack exchange,提问作者CodeoftheWarrior

