- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 typescript 新手。我正在使用javascript实现以前创建的功能。该函数接收一个对象。具有以下特性
tag
:将是string
。 children
:这是同一接口(interface)的数组(即ceProps
如下所示); style
:这将是包含样式的对象,例如(color
,fontSize
等)innerHTML
,src
等)interface Style {
[key : string ]: string;
}
interface ceProps {
tag: string;
style?: Style;
children?: ceProps[];
[key : string]: string;
}
const ce = ({tag, children, style, ...rest } : ceProps) => {
const element = document.createElement(tag);
//Adding properties
for(let prop in rest){
element[prop] = rest[prop];
}
//Adding children
if(children){
for(let child of children){
element.appendChild(ce(child))
}
}
//Adding styles
if(style){
for(let prop in style){
element.style[prop] = style[prop];
}
}
return element;
}
style
和
children
上的错误
Property
'style'
of type'Style | undefined'
is not assignable to string index type'string'
.ts(2411)Property
'children'
of type'ceProps[] | undefined'
is not assignable to string index type'string'
.ts(2411)
element[prop] = rest[prop];
行上还有另外一个错误,在
element.style[prop] = style[prop];
上也有相同的错误
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HTMLElement'. No index signature with a parameter of type 'string' was found on type 'HTMLElement'
最佳答案
回答你的问题
具有索引属性的可分配性
是的,接口(interface)不允许您同时定义字符串索引属性和使用以不同方式定义的特定字符串的属性。您可以使用intersection type解决此问题:
type ceProps =
& {
tag: string;
style?: Style;
children?: ceProps[];
}
& {
[key: string]: string;
};
这告诉Typescript
tag
将始终存在且始终为字符串,
style
可能存在或可能不存在,但在其中存在
Style
,并且
children
可能存在或不存在,而在
ceProps[]
存在那里。任何其他属性也可能存在,并且始终是字符串。
HTMLElement
问题是您指定
ceProps
可以包含任何字符串作为属性,但是
HTMLElement
从来没有任何字符串作为属性,它为它定义了特定的属性。
element
转换为
any
或将
element.style
转换为
any
来摆脱Typescript的检查,如下所示:
//Adding properties
for (const prop in rest) {
(element as any)[prop] = rest[prop];
}
if (style) {
for (const prop in style) {
(element.style as any)[prop] = style[prop];
}
}
但是,
这不是类型安全的。无需检查
ceProps
中的属性是否实际上是您创建的元素可以拥有或使用的属性。 HTML是相当宽容的-在大多数情况下,该属性只会被默默地忽略-但这比崩溃更令人生畏,因为您无法知道出了什么问题。
any
,您应该对
非常谨慎。 有时您必须这样做,但是它应该总是使您不舒服。
CSSStyleDeclaration
Typescript随附的
lib.dom.d.ts
文件包含HTML和本机Javascript中各种内容的定义。其中之一是
CSSStyleDeclaration
,一种用于设置HTML元素样式的类型。使用它代替您自己的
Style
声明:
type ceProps =
& {
tag: string;
style?: CSSStyleDeclaration;
children?: ceProps[];
}
& {
[key: string]: string;
};
执行此操作时,您不再需要使用
element.style
转换
(element.style as any)
-您可以使用以下代码:
//Adding styles
if (style) {
for (const prop in style) {
element.style[prop] = style[prop];
}
}
之所以可行,是因为现在Typescript知道您的
style
与
element.style
是同一种对象,因此可以正确解决。作为奖励,现在当您首先创建自己的
ceProps
时,如果您使用劣质属性(双赢),则会收到错误消息。
ceProps
的定义将允许您定义一个与
ce
一起使用的结构,以创建任何元素。但是,这里可能有一个更好的解决方案是使它通用。这样,我们可以跟踪哪个标记与
ceProps
的特定实例相关联。
type CeProps<Tag extends string = string> =
& {
tag: Tag;
style?: CSSStyleDeclaration;
children?: CeProps[];
}
& {
[key: string]: string;
};
(我将
ceProps
重命名为
CeProps
以更符合典型的Typescript命名风格,尽管当然欢迎您的项目使用其自己的风格。)
Tag
。拥有
Tag extends string
意味着
Tag
被限制为字符串-类似于
CeProps<number>
的错误。
= string
部分是默认参数,如果我们编写不带尖括号的
CeProps
,则表示
CeProps<string>
,即任何字符串。
CeProps<"a">
,然后我们知道
tag
不仅是任何字符串,而且特别是
"a"
。
const props: CeProps<"a"> = { tag: "a", href: "test" };
如果要在此处编写
tag: "b"
,则会出现错误-Typescript将要求它为
"a"
。您可以编写一个仅接受特定
CeProps
的函数,依此类推。
as const
关键字,Typescript也可以正确推断出这一点:
const props = { tag: "a" } as const;
Typescript将理解此
props
变量是
CeProps<"a">
值。 (实际上,从技术上讲,它将理解为
{ tag: "a"; }
类型,但是与
CeProps<"a">
兼容,并且可以将其传递给期望该功能的函数。)
CeProps
而不是仅对一个标签采用
|
的函数感兴趣,则可以使用
union type,它用
const aBold: CeProps<"b"> = { tag: "b" };
表示:
function takesBoldOrItalics(props: CeProps<"b" | "i">): void {
您可以使用
const anItalic = { tag: "i" } as const;
或
takesBoldOrItalics({ tag: "b" });
调用此函数,也可以像
{ tag: "a" }
一样直接调用它。但是,如果您尝试使用
keyof HTMLElementTagNameMap
调用它,则会收到错误消息。
lib.dom.d.ts
HTMLElementTagNameMap
中的另一个强大工具是
HTMLElement
,它为每个可能的HTML标签字符串提供了特定的
lib.dom.d.ts
。看起来像这样:
interface HTMLElementTagNameMap {
"a": HTMLAnchorElement;
"abbr": HTMLElement;
"address": HTMLElement;
"applet": HTMLAppletElement;
"area": HTMLAreaElement;
// ...
}
(从
lib.dom.d.ts
复制)
createElement
使用它来键入
lib.dom.d.ts
本身,例如:
createElement<K extends keyof HTMLElementTagNameMap>(
tagName: K,
options?: ElementCreationOptions,
): HTMLElementTagNameMap[K];
(我从
<K extends keyof HTMLElementTagNameMap>
复制了此代码,并添加了一些换行符以提高可读性。)
<Tag extends string>
部分。与
CeProps
上的
K
一样,这表示带有约束的类型参数
K
。因此,
keyof HTMLElementTagNameMap
必须是某种
keyof
。如果您不熟悉,
keyof { foo: number; bar: number; }
表示某种类型的“键”(属性名称)。因此
"foo" | "bar"
是
keyof HTMLElementTagNameMap
。
"a" | "abbr" | "address" | "applet" | "area" | ...
是
lib.dom.d.ts
-所有潜在HTML标记名称的联合(至少在
createElement
的最后一次更新中)。这意味着
tag
要求
HTMLElement
成为这些字符串之一(它还有其他重载,可以处理其他字符串并仅返回
CeProps
)。
ce({ tag: "image" })
中利用相同的功能:
type CeProps<Tag extends keyof HTMLElementTagNameMap = keyof HTMLElementTagNameMap> =
& {
tag: Tag;
style?: CSSStyleDeclaration;
children?: CeProps[];
}
& {
[key: string]: string;
};
现在,如果我们编写
ce({ tag: "img" })
而不是
Tag extends keyof HTMLElementTagNameMap
,我们将得到一个错误,而不是被静默接受,然后无法正常工作。
ce
,我们可以更精确地键入“rest”属性,这可以防止您犯错误,并且可以限制您需要在
CeProps
内部进行的强制类型转换。
MinimalCeProps
:
interface MinimalCeProps<Tag extends keyof HTMLElementTagNameMap> {
tag: Tag;
style?: CSSStyleDeclaration;
children?: CeProps[];
}
type CeProps<Tag extends keyof HTMLElementTagNameMap = keyof HTMLElementTagNameMap> =
& MinimalCeProps<Tag>
& Partial<Omit<HTMLElementTagNameMap[Tag], keyof MinimalCeProps<Tag>>>;
我将其分为两部分,一部分是
CeProps
,一部分是您想一直出现的部分,另一部分是完整的
Partial<Omit<HTMLElementTagNameMap[Tag], keyof MinimalCeProps<Tag>>>
,它与
Partial
相交。那是一个大嘴巴,但是我们稍后会分解。
Omit
和
HTMLElementTagNameMap[Tag]
进行业务。要分解,
Tag
是与createElement
对应的HTML元素。您会注意到,该类型与Omit
的返回类型相同。Omit<{ foo: string; bar: number; baz: 42[]; }, "foo" | "bar">
表示我们遗漏了作为第一个参数传入的某些类型的属性,如第二个字符串文字的并集所示。例如,{ bar: 42[]; }
将产生Omit<HTMLElementTagNameMap[Tag], keyof MinimalCeProps<Tag>>
。HTMLElementTagNameMap[Tag]
中,我们从MinimalCeProps<Tag>
中省略了已经是tag
中的属性的属性,即style
,children
和HTMLElementTagNameMap[Tag]
。这很重要,因为children
将具有CeProps[]
属性,而不会是Omit<HTMLElementTagNameMap[Tag], "children">
。我们可以只使用MinimalCeProps
,但我认为最好是透彻了解-我们希望Partial
为所有这些标签“赢”。Partial<{ foo: number; bar: string; baz: 42[]; }>
表示所有传递的类型的属性都应设为可选。因此{ foo?: number; bar?: string; baz?: 42[]; }
将是CeProps
。ce
中。其次,
element
本身可以利用它来减少对转换的依赖:
function ce<T extends keyof HTMLElementTagNameMap>(
{ tag, children, style, ...rest }: CeProps<T>,
): HTMLElementTagNameMap[T] {
const element = window.document.createElement(tag);
//Adding properties
const otherProps = rest as unknown as Partial<HTMLElementTagNameMap[T]>;
for (const prop in otherProps) {
element[prop] = otherProps[prop]!;
}
//Adding children
if (children) {
for (const child of children) {
element.appendChild(ce(child));
}
}
//Adding styles
if (style) {
for (const prop in style) {
element.style[prop] = style[prop];
}
}
return element;
}
在这里,由于
HTMLElementTagNameMap[T]
的类型声明,因此
createElement
自动获取正确的类型
otherProps
。然后,我们必须创建
any
“虚拟变量”,可悲的是,这需要进行一些强制转换-但是我们比强制转换为
!
更安全。我们还需要在
otherProps[prop]
上使用
!
-
undefined
告诉Typescript该值不是
CeProps
。这是因为您可以使用明确的
undefined
值创建
{ class: undefined }
,例如
for (const props in otherProps)
。由于这是一个奇怪的错误,因此似乎不值得一试。您只需保留的属性就不会有问题,因为它们不会出现在
ce
中。
createElement
的返回类型,就像键入
ce({ tag: "a" })
一样。这意味着,如果您执行
HTMLAnchorElement
,Typescript就会知道您正在获得ojit_code。
// Literal
ce({
tag: "a",
href: "test",
}); // HTMLAnchorElement
// Assigned to a variable without as const
const variable = {
tag: "a",
href: "test",
};
ce(variable); // Argument of type '{ tag: string; href: string; }' is not assignable to parameter of type 'CeProps<...
// Assigned to a variable using as const
const asConst = {
tag: "a",
href: "test",
} as const;
ce(asConst); // HTMLAnchorElement
// Giving invalid href property
ce({
tag: "a",
href: 42,
}); // 'number' is not assignable to 'string | undefined'
// Giving invalid property
ce({
tag: "a",
invalid: "foo",
}); // Argument of type '{ tag: "a"; invalid: string; }' is not assignable to parameter of type 'CeProps<"a">'.
// Object literal may only specify known properties, but 'invalid' does not exist in type 'CeProps<"a">'.
// Did you mean to write 'oninvalid'?
// Giving invalid tag
ce({ tag: "foo" }); // Type '"foo"' is not assignable to type '"object" | "link" | "small" | ...
关于javascript - 如何为在 typescript 中创建嵌套元素结构的函数创建接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59437256/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!