javascript - 未调用 TypeScript 装饰器和私有类方法
问题描述
我刚开始学习 TypeScript,我正在制作一个简单的“添加项目”应用程序,我按照教程进行操作
就是这个index.html
文件,不多说这个文件,因为它只是通过id
HMTL 元素来操作 DOM 的地方
这是app.css
文件:
* {
box-sizing: border-box;
}
html {
font-family: sans-serif;
}
body {
margin: 0;
}
label,
input,
textarea {
display: block;
margin: 0.5rem 0;
}
label {
font-weight: bold;
}
input,
textarea {
font: inherit;
padding: 0.2rem 0.4rem;
width: 100%;
max-width: 30rem;
border: 1px solid #ccc;
}
input:focus,
textarea:focus {
outline: none;
background: #fff5f9;
}
button {
font: inherit;
background: #ff0062;
border: 1px solid #ff0062;
cursor: pointer;
color: white;
padding: 0.75rem 1rem;
}
button:focus {
outline: none;
}
button:hover,
button:active {
background: #a80041;
border-color: #a80041;
}
.projects {
margin: 1rem;
border: 1px solid #ff0062;
}
.projects header {
background: #ff0062;
height: 3.5rem;
display: flex;
justify-content: center;
align-items: center;
}
#finished-projects {
border-color: #0044ff;
}
#finished-projects header {
background: #0044ff;
}
.projects h2 {
margin: 0;
color: white;
}
.projects ul {
list-style: none;
margin: 0;
padding: 1rem;
}
.projects li {
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.26);
padding: 1rem;
margin: 1rem;
}
.projects li h2 {
color: #ff0062;
margin: 0.5rem 0;
}
#finished-projects li h2 {
color: #0044ff;
}
.projects li h3 {
color: #575757;
font-size: 1rem;
}
.project li p {
margin: 0;
}
.droppable {
background: #ffe3ee;
}
#finished-projects .droppable {
background: #d6e1ff;
}
#user-input {
margin: 1rem;
padding: 1rem;
border: 1px solid #ff0062;
background: #f7f7f7;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>ProjectManager</title>
<link rel="stylesheet" href="app.css" />
<script src="dist/app.js" defer></script>
</head>
<body>
<template id="project-input">
<form>
<div class="form-control">
<label for="title">Title</label>
<input type="text" id="title" />
</div>
<div class="form-control">
<label for="description">Description</label>
<textarea id="description" rows="3"></textarea>
</div>
<div class="form-control">
<label for="people">People</label>
<input type="number" id="people" step="1" min="0" max="10" />
</div>
<button type="submit">ADD PROJECT</button>
</form>
</template>
<template id="single-project">
<li></li>
</template>
<template id="project-list">
<section class="projects">
<header>
<h2></h2>
</header>
<ul></ul>
</section>
</template>
<div id="app"></div>
</body>
</html>
该index.html
文件有一个脚本,dist/app.js
从中生成app.ts
. 这是app.ts
文件:
// autobind decorator
function autobind (_: any, _2: string, descriptor: PropertyDecorator) {
console.log('start autobind')
console.log(_, _2, descriptor)
const originalMethod = descriptor.value
const adjDescriptor: PropertyDecorator = {
configurable: true,
get () {
const boundFn = originalMethod.bind(this)
return boundFn
}
}
return adjDescriptor
}
// projectInput Class
class ProjectInput {
templateElement: HTMLTemplateElement
hostElement: HTMLDivElement
element: HTMLElement
titleInputElement: HTMLInputElement
descriptionInputElement: HTMLInputElement
peopleInputElement: HTMLInputElement
constructor () {
this.templateElement = document.getElementById(
'project-input'
)! as HTMLTemplateElement
this.hostElement = document.getElementById('app')! as HTMLDivElement
const importedNode = document.importNode(this.templateElement.content, true)
this.element = importedNode.firstElementChild as HTMLFormElement
this.element.id = 'user-input'
this.titleInputElement = this.element.querySelector(
'#title'
) as HTMLInputElement
this.descriptionInputElement = this.element.querySelector(
'#description'
) as HTMLInputElement
this.peopleInputElement = this.element.querySelector(
'#peole'
) as HTMLInputElement
this.configure()
this.attach()
}
private gatherUserInput (): [string, string, number] | void {
console.log('start gatherUserInput')
const enteredTitle = this.titleInputElement.value
const enteredDescription = this.descriptionInputElement.value
const enteredPeople = this.peopleInputElement.value
if (
enteredTitle.trim().length === 0 ||
enteredDescription.trim().length === 0 ||
enteredPeople.trim().length === 0
) {
alert('Invalid input, please try again')
return
} else {
return [enteredTitle, enteredDescription, +enteredPeople]
}
}
@autobind
private submitHandler (event: Event) {
event.preventDefault()
const userInput = this.gatherUserInput()
if (Array.isArray(userInput)) {
const [title, desc, people] = userInput
console.log(title, desc, people)
}
}
private configure () {
this.element.addEventListener('submit', this.submitHandler.bind(this))
}
private attach () {
this.hostElement.insertAdjacentElement('afterbegin', this.element)
}
}
const prjInput = new ProjectInput()
但它无法访问函数gatherUserInput
和装饰器autobind
,因为我尝试过console.log
但没有打印出来。
这是终端记录的内容:
[12:06:19 PM] Starting compilation in watch mode...
src/app.ts:3:37 - error TS2339: Property 'value' does not exist on type 'PropertyDecorator'.
3 const originalMethod = descriptor.value
~~~~~
src/app.ts:5:5 - error TS2322: Type '{ configurable: boolean; get(): any; }' is not assignable to type 'PropertyDecorator'.
Object literal may only specify known properties, and 'configurable' does not exist in type 'PropertyDecorator'.
5 configurable: true,
~~~~~~~~~~~~~~~~~~
src/app.ts:67:3 - error TS1241: Unable to resolve signature of method decorator when called as an expression.
Type 'PropertyDecorator' has no properties in common with type 'TypedPropertyDescriptor<(event: Event) => void>'.
67 @autobind
~~~~~~~~~
src/app.ts:67:4 - error TS2345: Argument of type 'TypedPropertyDescriptor<(event: Event) => void>' is not assignable to parameter of type 'PropertyDecorator'.
Type 'TypedPropertyDescriptor<(event: Event) => void>' provides no match for the signature '(target: Object, propertyKey: string | symbol): void'.
67 @autobind
~~~~~~~~
[12:06:24 PM] Found 4 errors. Watching for file changes.
请帮我解决这个问题,非常感谢,祝你有美好的一天
解决方案
快速查看代码后,自动绑定方法似乎没有使用正确的类型。
方法装饰器具有以下参数和参数类型
例如,自动绑定的参数看起来像这样
function
Autobind(target:any,methodName:string,propertyDescriptor:PropertyDescriptor){
.....
}
从上面的代码来看,在自动绑定装饰器中使用 PropertyDecarator 代替了 PropertyDescriptor。
如果自动绑定方法编写如下,则代码应该可以正常工作。
function autobind (_: any, _2: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
const adjDescriptor: PropertyDescriptor = {
configurable: true,
get () {
const boundFn = originalMethod.bind(this)
return boundFn
}
}
return adjDescriptor
}
推荐阅读
- c# - UWP 平铺图像拉伸和填充
- r - 计算字母序列中的熵
- ios - 如何在 iOS Swift 中将选定的 tableView 单元格保存到数组中?
- python - 使用gpu抓取rtsp相机python opencv的速度
- python-3.x - Python C 扩展是否像为 IO 任务一样为 CPU 任务发布 GIL?
- c - 在同一模块上交替使用旧的 sys_close 和新的 ksys_close
- javascript - 如何使用 vanilla JavaScript 在点击时更改图像
- html - 我似乎无法将标题和导航栏放在同一行
- python-3.x - Woocommerce API 将特定的 Json 数据分配给 Python 中的变量
- javascript - 来自 php json_encode 数据的 javascript parse.json 错误