ค้นหาเว็บไซต์

วิธีการกำหนดฟังก์ชันทั่วโลกใน TypeScript?


ฉันต้องการกำหนดฟังก์ชันระดับโลกที่สามารถใช้งานได้ทุกที่ โดยไม่จำเป็นต้องนำเข้าโมดูลเมื่อใช้งาน

ฟังก์ชันนี้มุ่งหมายที่จะทดแทนตัวดำเนินการนำทางอย่างปลอดภัย (?) ที่มีใน C#. เพื่อความอ่านง่าย ผมไม่ต้องการเติมชื่อโมดูลข้างหน้าฟังก์ชัน

Global.d.ts:

declare function s<T>(someObject: T | null | undefined, defaultValue?: T | null | undefined) : T;

Global.tsx:

///<reference path="Global.d.ts" />

export function s<T>(object: T | null | undefined, defaultValue: T | null = null = {} as T) : T {
    if (typeof object === 'undefined' || object === null)
        return defaultValue as T;
    else
        return object;
}

App.tsx (ไฟล์ TypeScript หลัก):

import 'Global';

ไฟล์ TSX อื่น (การใช้งานวิธี):

s(s(nullableVar).member).member; //Runtime error

โค้ดนี้คอมไพล์ได้ไม่มีปัญหา อย่างไรก็ตาม ในเบราว์เซอร์จะเกิดข้อผิดพลาด 's ไม่ใช่ฟังก์ชัน'.

คำตอบ #1

คุณกำหนดชนิดสำหรับคอมไพเลอร์ แต่ไม่ได้แนบมันไปกับเนมสเปซระดับโลก — window ในเบราว์เซอร์, global ใน Node แทนที่จะส่งออกจากโมดูล ให้แนบมัน สำหรับการใช้งานแบบ isomorphic ใช้บางอย่างเช่น...

function s() { ... }

// must cast as any to set property on window
const _global = (window /* browser */ || global /* node */) as any
_global.s = s

คุณยังสามารถละทิ้งไฟล์ .d.ts และประกาศชนิดในไฟล์เดียวกันโดยใช้ declare global เช่น ตัวอย่าง

// we must force tsc to interpret this file as a module, resolves
// "Augmentations for the global scope can only be directly nested in external modules or ambient module declarations."
// error
export {}

declare global {
  function s<T>(someObject: T | null | undefined, defaultValue?: T | null | undefined) : T;
}

const _global = (window /* browser */ || global /* node */) as any
_global.s = function<T>(object: T | null | undefined, defaultValue: T | null = null) : T {
  if (typeof object === 'undefined' || object === null)
    return defaultValue as T;
  else
    return object;
}

คำตอบ #2

ขอบคุณ @Romain Deneau คำตอบของเขาใช้ได้ผลสำหรับฉัน นี่คือตัวอย่างที่ฉันทำให้เรียบง่ายขึ้นเพื่อให้เข้าใจแนวคิดของคำตอบของเขาได้ง่ายขึ้น (ของฉันสมมติว่าสคริปต์รันบนเบราว์เซอร์ นอกจากนี้ ฉันยังละเว้นการลงลายเซ็นของฟังก์ชัน s)

กำหนดฟังก์ชันนอกคลาสใด ๆ

function s() {
    console.log("invoked s()!");
}

(window as any).s = s;

การใช้ฟังก์ชันระดับโลก s นี้จากคลาส TypeScript เป็นดังนี้;

declare var s;

export class MyClass {
    public static callFunctionS() {
        s();
    }
}

คำตอบ #3

global.ts(x) ต้องมีการปรับแต่งเล็กน้อยเพื่อให้เป็น "โมดูลแบบ global" ที่ถูกต้อง (โมดูลที่มีเพียงผลข้างเคียงเท่านั้น): ลบคำว่า export ออกและเพิ่มโค้ดบางส่วนเพื่อเสริมตัวแปร global คุณยังสามารถให้การประกาศ global ในไฟล์เดียวกันและลบ global.d.ts ได้

function _s<T>(object: T | null, defaultValue: T = {} as T) : T {
    return object == null
        ? defaultValue
        : object as T;
}

// Global declaration
declare var s: typeof _s;

// Global scope augmentation
var window = window || null;
const _global = (window || global) as any;
_global.s = _s;

ในการใช้งาน เพียงแค่ import โมดูลครั้งเดียว เช่น ใน App.tsx ผ่านการ import แบบ global: import './global';

ทดสอบด้วย mocha, chai, ts-node:

import { expect } from 'chai';
import './global'; // To do once at app bootstrapping

describe('global s()', () => {
    it('should replace null with empty object', () => {
        const result = s(null);
        expect(result).to.eql({});
    });

    it('should replace undefined with empty object', () => {
        const result = s(undefined);
        expect(result).to.eql({});
    });

    it('should replace null with the given default value', () => {
        const defVal = { def: 'val' };
        const result = s(null, defVal);
        expect(result).to.eql({ def: 'val' });
    });

    it('should preserve defined object', () => {
        const object = { bar: 'a' };
        const result = s(object);
        expect(result).to.eql(object);
    });
});

บทความที่เกี่ยวข้อง