TypeScript `this` 入参
<table class="d-block"><tbody class="d-block">
<tr class="d-block">
<td class="d-block comment-body markdown-body js-comment-body rgh-linkified-code">
<p>考察下面的示例代码:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">class</span> <span class="pl-en">MyClass</span> {
<span class="pl-k">constructor</span>(<span class="pl-k">protected</span> <span class="pl-v">foo</span><span class="pl-k">:</span> <span class="pl-c1">string</span>) {}
<p>@<span class="pl-smi">MyDecorator</span><br>
bar() {<br>
<span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>bar<span class="pl-pds">"</span></span>);<br>
}<br>
}</p>
<p><span class="pl-k">function</span> MyDecorator(<br>
<span class="pl-v">_target</span><span class="pl-k">:</span> <span class="pl-c1">any</span>,<br>
<span class="pl-v">_key</span><span class="pl-k">:</span> <span class="pl-c1">string</span>,<br>
<span class="pl-v">descriptor</span><span class="pl-k">:</span> <span class="pl-en">PropertyDescriptor</span><br>
) {<br>
<span class="pl-k"><span class="pl-k">const</span></span> original <span class="pl-k">=</span> <span class="pl-smi">descriptor</span>.<span class="pl-c1">value</span>;<br>
<span class="pl-smi">descriptor</span>.<span class="pl-c1">value</span> <span class="pl-k">=</span> <span class="pl-k">function</span>(<span class="pl-k">...</span><span class="pl-v">args</span><span class="pl-k">:</span> <span class="pl-c1">any</span>[]) {<br>
<span class="pl-c"><span class="pl-c">//</span> 🚨Property 'foo' does not exist on type 'PropertyDescriptor'.ts(2339)</span><br>
<span class="pl-c1">console</span>.<span class="pl-c1">log</span>(<span class="pl-c1">this</span>.<span class="pl-smi">foo</span>);<br>
<span class="pl-k">return</span> <span class="pl-smi">original</span>.<span class="pl-c1">apply</span>(<span class="pl-c1">this</span>, <span class="pl-smi">args</span>);<br>
};<br>
<span class="pl-k">return</span> <span class="pl-smi">descriptor</span>;<br>
}</p>
<p><span class="pl-k"><span class="pl-k">const</span></span> myClass <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">MyClass</span>(<span class="pl-s"><span class="pl-pds">"</span>erm<span class="pl-pds">"</span></span>);<br>
<span class="pl-smi">myClass</span>.<span class="pl-en">bar</span>();<br>
</p></pre></div><p></p>
<p>上面代码定义了一个类 <code>MyClass</code>,包含一个 <code>protected</code> 类型的 <code>foo</code> 属性。</p>
<p>同时定义了一个 <code>MyDecorator</code> 装饰器,在被装饰方法调用前访问上面的 <code>protected foo</code> 属性并且打印出来。</p>
<p>可以看到上面示例中,已经将 TypeScript 报错标识了出来,可以看到此时 <code>this</code> 所指的对象其实不对,指向了 <code>PropertyDescriptor</code>,所以在装饰器中试图访问 <code>protected foo</code> 时提示没有 <code>foo</code> 属性。</p>
<p>首先我们需要修正一下 <code>this</code> 的类型,因为该装饰器修饰的是类的方法,所以 <code>descriptor.value</code> 中 <code>this</code> 应该是被修饰方法所在的类才对。</p>
<div class="highlight highlight-source-diff"><pre>function MyDecorator(
_target: any,
_key: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
descriptor.value = function(...args: any[]) {
// 🚨Property 'foo' does not exist on type 'PropertyDescriptor'.ts(2339)
console.log((this as MyClass).foo);
return original.apply(this, args);
};
return descriptor;
}</pre></div>
<p>当我们试图通过强制类型转换修正 <code>this</code> 的类型时,发现新的错误出现了。因为 <code>foo</code> 被声明成了 <code>protected</code> 类型,它提示只能在 <code>MyClass</code> 中或其继承类中访问该属性。但我们明确知道,运行时 <code>descriptor.value</code> 确实是在这个类当中的。同时 Hover 到强制类型转换后的 <code>this</code> 上发现其类型还是 <code>PropertyDescriptor</code>,说明强制类型转换其实没生效。</p>
<p><img src="https://user-images.githubusercontent.com/3783096/59554334-0a4a7000-8fd4-11e9-8c18-24493f082544.png" alt="强制类型转换失败" style="max-width: 100%"></p>
<p align="center">强制类型转换失败</p>
<h2><code>this</code> 入参</h2>
<p>对于这种需要修正函数中 <code>this</code> 所指的场景,TypeScript 提供了一种机制,可以在函数入参列表中第一个位置处,手动写入 <code>this</code> 标识其类型。但这个 <code>this</code> 入参只作为一个形式上的参数,供 TypeScript 做静态检查时使用,编译后是不会存在于真实代码中的。</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">function</span> f(<span class="pl-v">this</span><span class="pl-k">:</span> <span class="pl-c1">void</span>) {
<span class="pl-c"><span class="pl-c">//</span> make sure `this` is unusable in this standalone function</span>
}</pre></div>
<p>像上面这样,<code>f</code> 被指定了 <code>this</code> 类型为 <code>void</code>,即 <code>f</code> 这个函数的函数体内,不允许使用 <code>this</code>。这有什么用呢,请看以下示例:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">interface</span> <span class="pl-en">UIElement</span> {
addClickListener(<span class="pl-en">onclick</span><span class="pl-k">:</span> (<span class="pl-v">this</span><span class="pl-k">:</span> <span class="pl-c1">void</span>, <span class="pl-v">e</span><span class="pl-k">:</span> <span class="pl-en">Event</span>) <span class="pl-k">=></span> <span class="pl-c1">void</span>)<span class="pl-k">:</span> <span class="pl-c1">void</span>;
}
<span class="pl-k">class</span> <span class="pl-en">Handler</span> {
<span class="pl-k">constructor</span>(<span class="pl-k">public</span> <span class="pl-v">info</span><span class="pl-k">:</span> <span class="pl-c1">string</span>) {}
onClickBad(<span class="pl-v">this</span><span class="pl-k">:</span> <span class="pl-en">Handler</span>, <span class="pl-v">e</span><span class="pl-k">:</span> <span class="pl-en">Event</span>) {
<span class="pl-c1">this</span>.<span class="pl-smi">info</span> <span class="pl-k">=</span> <span class="pl-smi">e</span>.<span class="pl-c1">type</span>;
}
}
<span class="pl-k">let</span> h <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">Handler</span>(<span class="pl-s"><span class="pl-pds">'</span>foo<span class="pl-pds">'</span></span>);
<span class="pl-c"><span class="pl-c">//</span> 🚨error</span>
<span class="pl-smi">uiElement</span>.<span class="pl-en">addClickListener</span>(<span class="pl-smi">h</span>.<span class="pl-smi">onClickBad</span>); </pre></div>
<p>上面 <code>uiElement.addClickListener</code> 声明了只接收一个不依赖于 <code>this</code> 上下文的函数做为回调,但我们传入的 <code>h.onClickBad</code> 声明为它执行时依赖于 <code>Handler</code> 这个上下文。因此显式地修正函数的执行上下文可让 TypeScript 检查出相关的错误。</p>
<p>回到文章开头的示例,我们就知道如何修正它了。</p>
<p>只需要将设置 <code>descriptor.value</code> 地方,为其添加上 <code>this</code> 入参即可保证正确的上下文了。</p>
<div class="highlight highlight-source-diff"><pre>function MyDecorator(
_target: any,
_key: string,
descriptor: PropertyDescriptor
) {
const original = descriptor.value;
<span class="pl-md"><span class="pl-md">-</span>descriptor.value = function(..args: any[]) {</span>
<span class="pl-mi1"><span class="pl-mi1">+</span>descriptor.value = function(this: MyClass, ...args: any[]) {</span>
console.log((this as MyClass).foo);
return original.apply(this, args);
};
return descriptor;
}</pre></div>
<h2>相关资源</h2>
<ul>
<li>TypeScript Handbook- Functions#this parameters</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div id="MySignature" role="contentinfo">
<div>
<img src="https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png" style="vertical-align: middle">
<strong>CC BY-NC-SA 署名-非商业性使用-相同方式共享</strong>
</div><br><br>
来源:https://www.cnblogs.com/Wayou/p/typescript_this_parameter.html
頁:
[1]