Cross-platform runtime for Taro framework providing DOM/BOM polyfills and mini-program bridge functionality
—
Comprehensive type definitions and interfaces that define the contracts and data structures for the Taro runtime system, providing type safety for cross-platform development.
The type system provides complete TypeScript definitions for:
// Base component interface
interface Component<T = Record<string, any>> {
data?: T
setData?(data: Partial<T>, callback?: () => void): void
$component?: any
[key: string]: any
}
// Page lifecycle interface
interface PageLifeCycle {
onLoad?(options: Record<string, unknown>): void
onShow?(): void
onHide?(): void
onReady?(): void
onUnload?(): void
onPullDownRefresh?(): void
onReachBottom?(): void
onPageScroll?(event: { scrollTop: number }): void
onShareAppMessage?(event: any): any
onShareTimeline?(): any
onTabItemTap?(event: { index: number, pagePath: string, text: string }): void
onResize?(event: { size: { windowWidth: number, windowHeight: number } }): void
}
// Show/hide lifecycle
interface Show {
onShow?(): void
onHide?(): void
}// Base app instance
interface AppInstance extends Show {
onLaunch?(options: any): void
onError?(error: string): void
globalData?: Record<string, any>
[key: string]: any
}
// React app instance
interface ReactAppInstance<T = AppInstance> extends Component<T>, AppInstance {
componentDidShow?(): void
componentDidHide?(): void
componentDidCatchError?(error: string): void
}// App implementation
class MyApp implements ReactAppInstance {
globalData = {
userInfo: null,
settings: {}
}
onLaunch(options: any) {
console.log('App launched with options:', options)
this.initializeApp()
}
onShow() {
console.log('App became active')
}
onHide() {
console.log('App went to background')
}
onError(error: string) {
console.error('App error:', error)
this.reportError(error)
}
// React lifecycle integration
componentDidShow() {
// React-specific show handling
}
componentDidHide() {
// React-specific hide handling
}
private initializeApp() { /* ... */ }
private reportError(error: string) { /* ... */ }
}// Base page instance
interface PageInstance extends PageLifeCycle {
route?: string
options?: Record<string, unknown>
data?: Record<string, any>
setData?(data: Record<string, any>, callback?: () => void): void
}
// React page instance
interface ReactPageInstance<T = PageProps> extends Component<T>, PageInstance {
// React component properties
props?: T
state?: any
setState?(updater: any, callback?: () => void): void
// React lifecycle methods
componentDidMount?(): void
componentWillUnmount?(): void
componentDidUpdate?(): void
// Mini-program lifecycle integration
componentDidShow?(): void
componentDidHide?(): void
}
// Page props interface
interface PageProps {
tid?: string
[key: string]: any
}// Page implementation
interface HomePageState {
userInfo: User | null
loading: boolean
posts: Post[]
}
class HomePage implements ReactPageInstance<PageProps> {
state: HomePageState = {
userInfo: null,
loading: false,
posts: []
}
// Mini-program lifecycle
onLoad(options: Record<string, unknown>) {
console.log('Page loaded with options:', options)
this.loadInitialData()
}
onShow() {
console.log('Page shown')
this.refreshUserStatus()
}
onReady() {
console.log('Page ready for interaction')
}
onPullDownRefresh() {
this.refreshData().then(() => {
wx.stopPullDownRefresh()
})
}
onReachBottom() {
if (!this.state.loading) {
this.loadMorePosts()
}
}
onShareAppMessage() {
return {
title: 'Check out these posts',
path: '/pages/home/home'
}
}
// React lifecycle
componentDidMount() {
// React-specific initialization
}
componentWillUnmount() {
// Cleanup
}
// React integration
componentDidShow() {
// Called from onShow
}
componentDidHide() {
// Called from onHide
}
private async loadInitialData() { /* ... */ }
private async refreshData() { /* ... */ }
private async loadMorePosts() { /* ... */ }
private refreshUserStatus() { /* ... */ }
}// Universal instance interface
interface Instance<T = Record<string, any>> extends Component<T>, Show, PageInstance {
// Combines all instance capabilities
}// Mini-program event structure
interface MpEvent {
type: string
timeStamp: number
target: {
id: string
dataset: Record<string, any>
[key: string]: any
}
currentTarget: {
id: string
dataset: Record<string, any>
[key: string]: any
}
detail?: any
touches?: Touch[]
changedTouches?: Touch[]
[key: string]: any
}
// Touch information
interface Touch {
identifier: number
pageX: number
pageY: number
clientX: number
clientY: number
}// Taro event interface
interface TaroEvent extends Event {
type: string
bubbles: boolean
cancelable: boolean
timeStamp: number
// Targets
target: TaroElement
currentTarget: TaroElement
// Mini-program integration
mpEvent?: MpEvent
// Control methods
stopPropagation(): void
stopImmediatePropagation(): void
preventDefault(): void
// State
defaultPrevented: boolean
eventPhase: number
}
// Event construction options
interface EventOptions {
bubbles?: boolean
cancelable?: boolean
detail?: any
}// Event handler with full typing
function handleUserInteraction(event: TaroEvent): void {
// Access event properties with type safety
console.log('Event type:', event.type)
console.log('Target element:', event.target.tagName)
console.log('Bubbles:', event.bubbles)
// Access mini-program specific data
if (event.mpEvent) {
console.log('Touch data:', event.mpEvent.touches)
console.log('Dataset:', event.mpEvent.target.dataset)
}
// Control event flow
if (shouldStopPropagation(event)) {
event.stopPropagation()
}
if (shouldPreventDefault(event)) {
event.preventDefault()
}
}
// Custom event creation
function createCustomEvent(type: string, options: EventOptions): TaroEvent {
return createEvent({
type,
bubbles: options.bubbles || false,
cancelable: options.cancelable || false,
detail: options.detail
})
}
// Event listener with type safety
element.addEventListener('tap', (event: TaroEvent) => {
// TypeScript ensures event is properly typed
handleUserInteraction(event)
})// Node type constants
const enum NodeType {
ELEMENT_NODE = 1,
TEXT_NODE = 3,
COMMENT_NODE = 8,
DOCUMENT_NODE = 9,
DOCUMENT_FRAGMENT_NODE = 11
}
// Base event target
interface TaroEventTarget {
addEventListener(type: string, listener: EventListener, options?: AddEventListenerOptions): void
removeEventListener(type: string, listener: EventListener): void
dispatchEvent(event: TaroEvent): boolean
}
// Base node interface
interface TaroNodeInterface extends TaroEventTarget {
// Identity
uid: string
sid: string
nodeType: NodeType
nodeName: string
// Tree structure
parentNode: TaroNode | null
childNodes: TaroNode[]
nextSibling: TaroNode | null
previousSibling: TaroNode | null
firstChild: TaroNode | null
lastChild: TaroNode | null
// Tree manipulation
appendChild(child: TaroNode): TaroNode
insertBefore(newChild: TaroNode, referenceChild: TaroNode | null): TaroNode
removeChild(child: TaroNode): TaroNode
replaceChild(newChild: TaroNode, oldChild: TaroNode): TaroNode
// Utilities
hasChildNodes(): boolean
}// Element interface
interface TaroElementInterface extends TaroNodeInterface {
// Element properties
tagName: string
id: string
className: string
// Content
innerHTML: string
textContent: string
// Attributes
attributes: Record<string, string>
dataset: Record<string, string>
// Style and classes
style: StyleInterface
classList: ClassListInterface
// Collections
children: TaroElement[]
// Attribute methods
getAttribute(name: string): string | null
setAttribute(name: string, value: string | number | boolean): void
removeAttribute(name: string): void
hasAttribute(name: string): boolean
// Selection methods
getElementById(id: string): TaroElement | null
getElementsByTagName(tagName: string): TaroElement[]
getElementsByClassName(className: string): TaroElement[]
// Focus
focus(): void
blur(): void
}
// Style interface
interface StyleInterface {
cssText: string
setProperty(property: string, value: string | null, priority?: string): void
getPropertyValue(property: string): string
removeProperty(property: string): void
[property: string]: string | Function
}
// ClassList interface
interface ClassListInterface {
length: number
add(...classNames: string[]): void
remove(...classNames: string[]): void
toggle(className: string, force?: boolean): boolean
contains(className: string): boolean
item(index: number): string | null
toString(): string
[index: number]: string
}// Type-safe element manipulation
function setupElement(element: TaroElement): void {
// Properties with type safety
element.id = 'unique-id'
element.className = 'container active'
element.textContent = 'Hello World'
// Attributes
element.setAttribute('data-test', 'value')
element.setAttribute('aria-label', 'Button')
// Style manipulation
element.style.setProperty('background-color', '#ffffff')
element.style.color = 'black'
// Class manipulation
element.classList.add('visible')
element.classList.toggle('highlighted')
// Tree operations
const child = document.createElement('span')
element.appendChild(child)
}
// Custom element type
interface CustomElementInterface extends TaroElementInterface {
customProperty: string
customMethod(): void
}
class CustomElement implements CustomElementInterface {
// Implement all TaroElementInterface methods
customProperty = 'custom value'
customMethod() {
console.log('Custom method called')
}
// ... implement other required methods
}// DOM update payload
interface UpdatePayload {
path: string // Dot-notation path (e.g., "root.cn.[0].v")
value: any // New value for the path
type?: 'set' | 'splice' | 'remove'
}
// Update batch
interface UpdateBatch {
payloads: UpdatePayload[]
callback?: () => void
}
// Mini-program data structure
interface MiniData {
[key: string]: any
// Common properties
cn?: MiniData[] // Child nodes
v?: string // Text value
st?: StyleData // Style data
cl?: string // Class list
id?: string // Element ID
}
// Style data for mini-programs
interface StyleData {
[property: string]: string | number
}
// Hydrated component data
interface HydratedData extends MiniData {
// Additional hydration metadata
_hydrated?: boolean
_path?: string
_uid?: string
}// Create update payload
function createUpdatePayload(element: TaroElement, property: string, value: any): UpdatePayload {
return {
path: `${element._path}.${property}`,
value,
type: 'set'
}
}
// Batch updates
function batchUpdates(updates: UpdatePayload[]): UpdateBatch {
return {
payloads: updates,
callback: () => {
console.log('Batch update completed')
}
}
}
// Process mini-program data
function processMiniData(data: MiniData): void {
if (data.cn) {
data.cn.forEach(child => processMiniData(child))
}
if (data.v) {
console.log('Text content:', data.v)
}
if (data.st) {
console.log('Styles:', data.st)
}
}
// Hydration result handling
function handleHydratedData(hydrated: HydratedData): void {
if (hydrated._hydrated) {
console.log('Data is hydrated')
console.log('Path:', hydrated._path)
console.log('UID:', hydrated._uid)
}
}// Page configuration options
interface PageConfig {
// Navigation bar
navigationBarTitleText?: string
navigationBarBackgroundColor?: string
navigationBarTextStyle?: 'black' | 'white'
// Background
backgroundColor?: string
backgroundTextStyle?: 'dark' | 'light'
backgroundColorTop?: string
backgroundColorBottom?: string
// Pull refresh
enablePullDownRefresh?: boolean
onReachBottomDistance?: number
// Custom navigation
navigationStyle?: 'default' | 'custom'
// Platform specific
[key: string]: any
}
// Component configuration
interface ComponentConfig {
// Component options
options?: {
multipleSlots?: boolean
addGlobalClass?: boolean
virtualHost?: boolean
styleIsolation?: 'isolated' | 'apply-shared' | 'shared'
}
// External classes
externalClasses?: string[]
// Relations
relations?: Record<string, RelationConfig>
// Observers
observers?: Record<string, ObserverFunction>
// Lifecycle
lifetimes?: {
created?(): void
attached?(): void
ready?(): void
moved?(): void
detached?(): void
}
// Page lifecycle (for components in pages)
pageLifetimes?: {
show?(): void
hide?(): void
resize?(size: { windowWidth: number, windowHeight: number }): void
}
// Data and methods
data?: Record<string, any>
methods?: Record<string, Function>
}
// Component relation configuration
interface RelationConfig {
type: 'parent' | 'child' | 'ancestor' | 'descendant'
target?: string
linked?(target: any): void
linkChanged?(target: any): void
unlinked?(target: any): void
}
// Observer function type
type ObserverFunction = (newVal: any, oldVal: any, changedPath: string) => void// Page configuration
const homePageConfig: PageConfig = {
navigationBarTitleText: 'Home Page',
navigationBarBackgroundColor: '#ffffff',
navigationBarTextStyle: 'black',
backgroundColor: '#f5f5f5',
enablePullDownRefresh: true,
onReachBottomDistance: 50
}
// Component configuration
const listComponentConfig: ComponentConfig = {
options: {
multipleSlots: true,
addGlobalClass: true,
styleIsolation: 'isolated'
},
externalClasses: ['custom-item-class'],
relations: {
'./list-item': {
type: 'child',
linked(target) {
console.log('List item linked:', target)
},
unlinked(target) {
console.log('List item unlinked:', target)
}
}
},
observers: {
'items.**': function(newVal, oldVal, changedPath) {
console.log('Items changed:', changedPath, newVal)
}
},
lifetimes: {
attached() {
console.log('Component attached')
},
detached() {
console.log('Component detached')
}
},
pageLifetimes: {
show() {
console.log('Page containing component shown')
}
},
data: {
items: [],
loading: false
},
methods: {
addItem(item: any) {
this.setData({
items: [...this.data.items, item]
})
}
}
}// Environment interface
interface Env {
window: Window | Record<string, never>
document: Document | Record<string, never>
}
// Current runtime state
interface Current {
app: AppInstance | null
router: Router | null
page: PageInstance | null
preloadData?: any
}
// Router state
interface Router {
params: Record<string, unknown>
path: string
$taroPath: string
onReady: string
onHide: string
onShow: string
exitState?: any
}// Generic function type
type TFunc = (...args: any[]) => any
// Event listener type
type EventListener = (event: TaroEvent) => void | boolean
// Timer handler type
type TimerHandler = string | Function
// Frame request callback
type FrameRequestCallback = (timestamp: number) => void
// Mutation callback
type MutationCallback = (mutations: MutationRecord[], observer: MutationObserver) => void// Options interface
interface Options {
prerender: boolean
debug: boolean
}
// Cache interface
interface CacheInterface<T = any> {
set(key: string, value: T): void
get(key: string): T | undefined
has(key: string): boolean
delete(key: string): boolean
clear(): void
size: number
}
// Performance interface
interface PerformanceInterface {
start(id: string): void
stop(id: string, now?: number): void
delayStop(id: string, delay?: number): void
}// Type-safe utility usage
function createUtilityFunction(): TFunc {
return (...args: any[]) => {
console.log('Arguments:', args)
return args[0]
}
}
// Event handling with proper types
function setupEventHandling(element: TaroElement): void {
const handler: EventListener = (event: TaroEvent) => {
console.log('Event handled:', event.type)
return false // Prevent further handling
}
element.addEventListener('tap', handler)
}
// Performance monitoring with types
function monitorPerformance(perf: PerformanceInterface): void {
perf.start('operation')
// ... perform operation
perf.stop('operation')
}
// Cache usage with types
function setupCache(): CacheInterface<string> {
const cache = new RuntimeCache<string>()
cache.set('key1', 'value1')
const value = cache.get('key1') // TypeScript knows this is string | undefined
return cache
}// Component with data constraints
interface ComponentWithData<T extends Record<string, any> = Record<string, any>> extends Component<T> {
data: T
setData(updates: Partial<T>): void
}
// Page with props constraints
interface PageWithProps<P extends PageProps = PageProps> extends ReactPageInstance<P> {
props: P
}
// Event handler with payload constraints
interface EventHandlerWithPayload<T = any> {
(event: TaroEvent & { detail: T }): void
}// Platform-specific types
type PlatformSpecific<T, P extends 'web' | 'miniprogram'> =
P extends 'web' ? T & WebSpecific : T & MiniprogramSpecific
interface WebSpecific {
webOnlyProperty: string
}
interface MiniprogramSpecific {
mpOnlyProperty: string
}
// Optional lifecycle based on platform
type ConditionalLifecycle<P extends 'web' | 'miniprogram'> =
P extends 'web' ? WebLifecycle : MiniprogramLifecycle
interface WebLifecycle {
componentDidMount?(): void
componentWillUnmount?(): void
}
interface MiniprogramLifecycle {
onLoad?(): void
onUnload?(): void
}// Generic component with constraints
class TypedComponent<T extends Record<string, any>> implements ComponentWithData<T> {
data: T
constructor(initialData: T) {
this.data = initialData
}
setData(updates: Partial<T>): void {
this.data = { ...this.data, ...updates }
}
}
// Usage
interface MyComponentData {
count: number
message: string
}
const component = new TypedComponent<MyComponentData>({
count: 0,
message: 'Hello'
})
component.setData({ count: 1 }) // Type-safe updates
// Platform-specific implementation
function createPlatformComponent<P extends 'web' | 'miniprogram'>(
platform: P
): PlatformSpecific<Component, P> {
// Implementation varies by platform
if (platform === 'web') {
return {
webOnlyProperty: 'web-specific'
} as any
} else {
return {
mpOnlyProperty: 'miniprogram-specific'
} as any
}
}import {
PROPERTY_THRESHOLD,
TARO_RUNTIME,
HOOKS_APP_ID,
SET_DATA,
PAGE_INIT,
ROOT_STR,
HTML,
HEAD,
BODY,
APP,
CONTAINER,
DOCUMENT_ELEMENT_NAME,
DOCUMENT_FRAGMENT,
ID,
UID,
CLASS,
STYLE,
FOCUS,
VIEW,
STATIC_VIEW,
PURE_VIEW,
CLICK_VIEW,
PROPS,
DATASET,
OBJECT,
VALUE,
INPUT,
CHANGE,
CUSTOM_WRAPPER,
TARGET,
CURRENT_TARGET,
TYPE,
CONFIRM,
TIME_STAMP,
KEY_CODE,
TOUCHMOVE,
DATE,
SET_TIMEOUT,
COMPILE_MODE,
CATCHMOVE,
CATCH_VIEW,
COMMENT,
ON_LOAD,
ON_READY,
ON_SHOW,
ON_HIDE,
OPTIONS,
EXTERNAL_CLASSES,
EVENT_CALLBACK_RESULT,
BEHAVIORS,
A,
CONTEXT_ACTIONS
} from '@tarojs/runtime'
// Core system constants
const PROPERTY_THRESHOLD: 2046 // Max property count for setData
const TARO_RUNTIME: 'Taro runtime'
const HOOKS_APP_ID: 'taro-app'
// Page context actions
enum CONTEXT_ACTIONS {
INIT = '0', // Initialize new page
RESTORE = '1', // Restore cached page
RECOVER = '2', // Recover from cache
DESTORY = '3' // Clean up page context
}
// DOM node names
const ROOT_STR: 'root'
const HTML: 'html'
const HEAD: 'head'
const BODY: 'body'
const APP: 'app'
const CONTAINER: 'container'
const DOCUMENT_ELEMENT_NAME: '#document'
const DOCUMENT_FRAGMENT: 'document-fragment'
const COMMENT: 'comment'
// Element types
const VIEW: 'view'
const STATIC_VIEW: 'static-view'
const PURE_VIEW: 'pure-view'
const CLICK_VIEW: 'click-view'
const CATCH_VIEW: 'catch-view'
const CUSTOM_WRAPPER: 'custom-wrapper'
// Attribute names
const ID: 'id'
const UID: 'uid'
const CLASS: 'class'
const STYLE: 'style'
const PROPS: 'props'
const DATASET: 'dataset'
const VALUE: 'value'
// Event types
const INPUT: 'input'
const CHANGE: 'change'
const FOCUS: 'focus'
const TOUCHMOVE: 'touchmove'
const TARGET: 'target'
const CURRENT_TARGET: 'currentTarget'
const TYPE: 'type'
const CONFIRM: 'confirm'
const TIME_STAMP: 'timeStamp'
const KEY_CODE: 'keyCode'
const EVENT_CALLBACK_RESULT: 'e_result'
// Lifecycle events
const ON_LOAD: 'onLoad'
const ON_READY: 'onReady'
const ON_SHOW: 'onShow'
const ON_HIDE: 'onHide'
// Mini-program specific
const COMPILE_MODE: 'compileMode'
const CATCHMOVE: 'catchMove'
const OPTIONS: 'options'
const EXTERNAL_CLASSES: 'externalClasses'
const BEHAVIORS: 'behaviors'
// Other constants
const OBJECT: 'object'
const DATE: 'Date'
const SET_TIMEOUT: 'setTimeout'
const A: 'a'// Use constants for consistent string values
function createTaroElement(tagName: string = VIEW): TaroElement {
const element = new TaroElement()
element.tagName = tagName
return element
}
// Page context management
function handleContextAction(action: CONTEXT_ACTIONS): void {
switch (action) {
case CONTEXT_ACTIONS.INIT:
initializePage()
break
case CONTEXT_ACTIONS.RESTORE:
restorePage()
break
case CONTEXT_ACTIONS.RECOVER:
recoverPage()
break
case CONTEXT_ACTIONS.DESTORY:
cleanupPage()
break
}
}
// Property threshold checking
function safeSetData(data: Record<string, any>): void {
const propertyCount = Object.keys(data).length
if (propertyCount > PROPERTY_THRESHOLD) {
console.warn(`Property count ${propertyCount} exceeds threshold ${PROPERTY_THRESHOLD}`)
// Batch the updates or use alternative approach
} else {
// Safe to set data
this.setData(data)
}
}
// Event type checking
function isUserInputEvent(event: TaroEvent): boolean {
return event.type === INPUT || event.type === CHANGE
}
// DOM tree checking
function isRootElement(element: TaroElement): boolean {
return element.nodeName === ROOT_STR || element.nodeName === HTML
}The comprehensive type system ensures type safety across all aspects of Taro runtime development, providing clear contracts for components, events, DOM operations, and platform integrations while maintaining flexibility for custom implementations and platform-specific optimizations.
Install with Tessl CLI
npx tessl i tessl/npm-tarojs--runtime